How to add a custom library (e.g. glew) to mingw-w64? - c

I'm using windows and my goal is to add the glew library (http://glew.sourceforge.net/index.html) to mingw. I have downloaded mingw-w64 via GitHub (https://github.com/mstorsjo/llvm-mingw/releases/tag/20210423). It comes with a "bin", "lib" and "include" folder. Within the "bin" folder I do "make" to execute my project's makefile which inlcudes the line
LDLIBS=-lm -lGL -lGLEW -lglfw
I have copied "glew32.lib" to "mingw/lib", "GL/glew.h" and "GL/wglew.h" to "mingw/include/GL" and "bin/glew32.dll" to "mingw/bin".
In my source code i have included the header file with
#include <GL/glew.h>
When i do "make" i get an error on that line:
GL/glew.h: No such file or directory
How do you add custom libraries like glew to mingw?

When using a library use the -I compiler flag to tell the compiler where to find the include files (in your case the path containing the GL folder) and the -L linker flag to tell the linker where to find the libraries.
To link with the library use the -l flag. The library itself is a a lib*.a file (or lib*.dll.a for shared libraries). For the -l flag the library is specified without prefix and suffix, so if your library is called libglew.a the flag will be -lglew.
It is also possible to specified the full path to the lib*.a file instead of -L and -l flags, and with MinGW, if you have the .dll file you can even try to specify the path of the .dll file and the linker will know what to do.

Related

Why gcc under Windows O.S. produces a .o instead of a .lib file when compiling static libraries?

I am using gcc 8.1.0 on Windows. To install it I set up Code::Blocks on my computer and updated the environment variable list by adding the path to the gcc.exe program within the installation folder of CodeBlocks. The file editor I used was the built-in editor in Visual Studio. The terminal to compile was the power shell from Visual Studio as well.
In the library development folder I have the files mul.c and mul.h. Their content is irrelevant.
To compile the library I use the command:
gcc -c mul.c
When I run it, it creates a file object mul.o and not mul.lib. I needed to use the option -o mul.lib to successfully create the desired extension file. After placing the header, the .lib file and the main.c in the same parent folder I am obvioudly able to build the executable by running.
gcc main.c -I./include -L/static -lmul -o my_program.exe
I have two questions:
Why does gcc produces a .o if I am in a Windows environment?
I followed a tutorial that compile the static library under Linux and it names it libmul.o, in this way the -lmul option is able to retrieve the library. But if I call my generated static library libul.lib it generates the error:
C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/x86_64-w64-ingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot find -lmul
collect2.exe: error: ld returned 1 exit status
Are these a normal behaviours by gcc, or is it side effect of making gcc available just by updating the Windows environmental variables list?
Thank you to the community in advance.
GCC comes from the *nix world where libraries have the .a extension. When using GCC+MinGW this remains the case.
Shared libraries in MinGW are .dll files but their libraries for linking are .dll.a files.
The advantage of .a files is that a lot of sources build out of the box on Windows with MinGW, especially when using MSYS2 shell.
If you use -l it will look for .a (or .dll.a for shared build) file adding the lib prefix and the extension automatically.
So -lmul will look for libmul.a (static, e.g. when --static linker flag is given) or libmul.dll.a (shared).
By the way, you are using quite an old GCC 8.1.0.
As I write this current version is 12.2.0. Check https://winlibs.com/ for a standalone download (instructions on how to configure in Code::Blocks are on the site) or use MSYS2's package manager pacman.

I set the rpath with gcc in MYSYS2 when compiling, but the program can't find it when running, so why?

In my working directory there are main.c and a folder named lib with libtest.dll in it.
I use
$ gcc main.c -ltest -L ./lib -Wl,-rpath=./lib
to compile, and the compilation process is no problem (no warning and error). But when i run a.exe the system remind
D:/MYSY2/home/user/code/a.exe: error while loading shared libraries: libtest.dll: cannot open shared object file: No such file or directory
So why the library can be found when compiling but not when running?
Shared libraries on Windows are .dll files and the are located by looking in the same folder as the running .exe file, or if that doesn't work by looking in the locations specified by the PATH environment variable.
So the best solution is to copy the .dll file(s) in the same location as the .exe file(s).
For distribution of your application you can use copypedeps -r from https://github.com/brechtsanders/pedeps to copy the .exe file along with any dependency .dll files, in case you are not certain which files are needed.

Forcing gcc to only look in one directory for library files

So I am making a C application and I have all the library files .so , .a etc in a ./lib directory in the same directory as my C application.
I am compiling my C application with the -L./lib flag.
But it seems to me that gcc still looks for libraries within /usr/lib /usr/local/lib etc .
Is there a way to force gcc to only look for library files in my ./lib directory?
So if I remove the ./lib folder the application won't compile because it can't find the libraries.

What does g++ / gcc do when asked to link against .a files?

I'm reading a tutorial about C development with the SDL library on MingW and Windows. (The tutorial is actually about C++ but I'm assuming installation and building is the same).
The tutorial gives the following command for building the program:
g++ 01_hello_SDL.cpp -IC:\mingw_dev_lib\include\SDL2 -LC:\mingw_dev_lib\lib -w -Wl,-subsystem,windows -lmingw32 -lSDL2main -lSDL2 -o 01_hello_SDL
In this command we use -L and -l to tell g++ where to find .a files (not .DLL or .so files) for linking. However, as far as I understand - this command is supposed to dynamically link the library. And as we know, .a files are static library files. What am I missing?
Why are we not linking with the .DLL file of the library, but instead we link with these .a files? When executing, the .DLL file will have to be present near the executable, but the .a won't have to as far as I understand. Again, what am I missing?
-l is not only for dynamic libraries. It can also be used to link static libraries.
On Linux, it is normal to directly link with a .so file (equivalent to a .dll). On Windows, it is still possible to do this (I think), but it is more normal to link with a .lib file called an import library, which wraps the .dll (you link to the .lib and the .lib links to the .dll). Since you are not using the Microsoft toolchain, it's possible that your toolchain still uses import libraries, but calls them .a files instead of .lib files.

Using protoc inside CMakeLists from a non-standard directory gives "cannot open shared object file: No such file or directory" error

I have a C application using CMake to generate Makefiles on Linux. The application contains .c as well as .proto files. Now I need to genearte .pb-c.c and .pb-c.h using protoc command in the CMakeLists.txt so that when I do cmake . the cmake generates the corresponding .pb-c and .pb-h. The protoc is used as:
execute_process(COMMAND bash -c "${PROTOC_PATH} --c_out=${CMAKE_CURRENT_SOURCE_DIR}/ --proto_path=${PROTO_DIR}/ ${PROTO_DIR}/*.proto")
The problem is that my protoc binary and related .so file is not in /usr/bin and /usr/lib or /usr/local/bin and /usr/local/lib. They are in a directory inside the project - $HOME/project-name/dependencies/bin/protoc and $HOME/project-name/dependencies/lib/libprotobuf.so.12
Due to this I am getting error - error while loading shared libraries: libprotobuf.so.12: cannot open shared object file: No such file or directory
But if I give the command as
execute_process(COMMAND bash -c "protoc--c_out=${CMAKE_CURRENT_SOURCE_DIR}/ --proto_path=${PROTO_DIR}/ ${PROTO_DIR}/*.proto") and run cmake . then it works fine as linker is able to get the .so file from /usr/lib
Mentioned below is a part of my CMakeLists.txt file
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath=${PROTOC_LIB_PATH} -L${PROTOC_LIB_PATH} -lprotobuf")
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,-rpath=${PROTOC_LIB_PATH} -L${PROTOC_LIB_PATH} -lprotobuf")
execute_process(COMMAND bash -c "${PROTOC_PATH} --c_out=${CMAKE_CURRENT_SOURCE_DIR}/ --proto_path=${PROTO_DIR}/ ${PROTO_DIR}/*.proto")
But it's not working due to aforementioned error.
Also for those who might say it's a duplicate I have looked into and tried the following SO questions:
Turning on linker flags with CMake
I don't understand -Wl,-rpath -Wl,
CMake link to external library
Does cmake have something like target_link_options?
CMAKE RPATH not working - could not find shared object file
https://serverfault.com/q/279068/435497
How to add linker flag for libraries with CMake?
https://serverfault.com/a/926072/435497
If you do not have a special use case, you do not need to call protoc yourself. Let CMake do this for you.
Have a look at: https://cmake.org/cmake/help/v3.16/module/FindProtobuf.html
and Cmake : find protobuf package in custom directory
I found this link which has a script showing how to create a PROTOBUF_GENERATE_C function which can then be used to generate the .pb-c abd .pb-h files.
From the above script I got the idea to make use of find_program which is similar to find_library in a way that it lets you pass the PATHS/PATH option so that CMake looks for the required program in the mentioned path.

Resources