Issue
I'm currently trying my hand at C programming for Windows. I have Windows 11, I code on VS Code, and I have installed MinGW and correctly added it to the PATH. The problem is that I can't link my program to the libiphlapi
and ws2_32
libraries.
This is my working environment :
tree /F
D:.
│ Makefile
│
├───.vscode
│ settings.json
│
├───build
├───include
│ windows_backup_scheduler.h
│
├───obj
│ hwid.o
│ main.o
│
└───src
hwid.c
main.c
Makefile:
BUILD_DIR := build
INCLUDE_DIR := include
OBJ_DIR := obj
SRC_DIR := src
NAME := windows_backup_scheduler.exe
CC := gcc
CFLAGS := -m64 -fPIE -Wall -Wextra -Werror -pedantic -g3
LFLAGS := -I$(INCLUDE_DIR) -I"C:\MinGW\include" -L"C:\MinGW\x86_64-w64-mingw32\lib" -liphlpapi -lws2_32 -static-libgcc
SRC_FILES := $(wildcard $(SRC_DIR)/*.c)
OBJ_FILES := $(patsubst $(SRC_DIR)/%.c, $(OBJ_DIR)/%.o, $(SRC_FILES))
TARGET := $(BUILD_DIR)/$(NAME)
all: $(TARGET)
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) $(LFLAGS) -c $< -o $@
$(TARGET): $(OBJ_FILES)
$(CC) $(CFLAGS) $(LFLAGS) -o $@ $^
clean:
@del /Q $(OBJ_DIR)\*.o
fclean: clean
@del /Q $(BUILD_DIR)\$(NAME)
re: fclean all
windows_backup_scheduler.h
#ifndef WINDOWS_BACKUP_SCHEDULER_H
#define WINDOWS_BACKUP_SCHEDULER_H
#ifndef NULL
#define NULL (void *)0;
#endif
#include <stdio.h>
#include <tchar.h>
#include <winsock2.h>
#include <iphlpapi.h>
#include <windows.h>
char *GetMACAddress(void);
#endif
main.c
#include <windows_backup_scheduler.h>
int main(void)
{
printf("MAC %s\n", GetMACAddress());
return (0);
}
hwid.c
#include <windows_backup_scheduler.h>
char *GetMACAddress(void)
{
IP_ADAPTER_INFO* AdapterInfo = NULL;
ULONG ulBufLen = 0;
DWORD dwStatus = 0;
char* macAddr = NULL;
if (GetAdaptersInfo(AdapterInfo, &ulBufLen) == ERROR_BUFFER_OVERFLOW) {
if ((AdapterInfo = malloc(ulBufLen)) == NULL) {
return (NULL);
}
}
if ((dwStatus = GetAdaptersInfo(AdapterInfo, &ulBufLen)) != ERROR_SUCCESS) {
free(AdapterInfo);
return (NULL);
}
if ((macAddr = (char*)malloc(18)) == NULL) {
free(AdapterInfo);
return (NULL);
}
snprintf(macAddr, 18, "%02X-%02X-%02X-%02X-%02X-%02X",
AdapterInfo[0].Address[0], AdapterInfo[0].Address[1],
AdapterInfo[0].Address[2], AdapterInfo[0].Address[3],
AdapterInfo[0].Address[4], AdapterInfo[0].Address[5]);
free(AdapterInfo);
return (macAddr);
}
When I try to compile I get this:
D:\WMP\Training\Windows_Backup_Scheduler>make re
Unable to find D:\WMP\Training\Windows_Backup_Scheduler\build\windows_backup_scheduler.exe
gcc -m64 -fPIE -Wall -Wextra -Werror -pedantic -g3 -Iinclude -I"C:\MinGW\include" -L"C:\MinGW\x86_64-w64-mingw32\lib" -liphlpapi -lws2_32 -static-libgcc -c src/hwid.c -o obj/hwid.o
gcc -m64 -fPIE -Wall -Wextra -Werror -pedantic -g3 -Iinclude -I"C:\MinGW\include" -L"C:\MinGW\x86_64-w64-mingw32\lib" -liphlpapi -lws2_32 -static-libgcc -c src/main.c -o obj/main.o
gcc -m64 -fPIE -Wall -Wextra -Werror -pedantic -g3 -Iinclude -I"C:\MinGW\include" -L"C:\MinGW\x86_64-w64-mingw32\lib" -liphlpapi -lws2_32 -static-libgcc -o build/windows_backup_scheduler.exe obj/hwid.o obj/main.o
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: obj/hwid.o: in function `GetMACAddress':
D:\WMP\Training\Windows_Backup_Scheduler/src/hwid.c:10: undefined reference to `GetAdaptersInfo'
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: D:\WMP\Training\Windows_Backup_Scheduler/src/hwid.c:15: undefined reference to `GetAdaptersInfo'
collect2.exe: error: ld returned 1 exit status
make: *** [Makefile:21: build/windows_backup_scheduler.exe] Error 1
VSCode found the header files, and libiphlapi.a
and ws2_32.a
are in C:\MinGW\x86_64-w64-mingw32\lib
and the headers in C:\MinGW\include
Can you provide me with a solution?
Solution
Your variables are not separated out properly.
You need to put flags for the compiler in one set of variables and flags for the linker in a different set of variables. Here for example:
LFLAGS := -I$(INCLUDE_DIR) -I"C:\MinGW\include" -L"C:\MinGW\x86_64-w64-mingw32\lib" -liphlpapi -lws2_32 -static-libgcc
This is wrong because -I
is a compiler option, while -L
and -l
are linker options. You should not have them in the same variable because you don't need to pass compiler flags to the linker and you definitely don't want to pass linker flags to the compiler.
But the main direct problem you are seeing with your link error is that you must put the libraries (-l....
) after the object files in the link line. Most linkers are "single-pass" linkers which means they only link symbols that they need at the time they process the library on the command line, and the linker won't know what symbols are needed by the libraries until after it handles the object files.
If you wanted to use the standard make variables (which of course you don't have to do if you don't want to) you should use:
CC := gcc
CFLAGS := -m64 -fPIE -Wall -Wextra -Werror -pedantic -g3
CPPFLAGS := -I$(INCLUDE_DIR) -I"C:\MinGW\include"
LDFLAGS := -L"C:\MinGW\x86_64-w64-mingw32\lib"
LDLIBS := -liphlpapi -lws2_32 -static-libgcc
Then you would write:
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
$(TARGET): $(OBJ_FILES)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
Answered By - MadScientist Answer Checked By - David Goodson (WPSolving Volunteer)