Compiling a C program and linking - c

Do I understand it correctly on how to use cmake for linking
cmake_minimum_required(VERSION 3.2)
project(Sdltest)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -lmingw32 -lSDL2main -lSDL2")
set(SOURCE_FILES main.c)
add_executable(Sdltest ${SOURCE_FILES})
I'm trying to link the sdl2 to my project but I get a lot of errors.
like /src/mingw-org-wsl/4.0-dev/src/libcrt/crt/main.c:91: undefined reference to `WinMain#16'
When I use gcc on cmd, it compiles perfectly
gcc main.c -o test -Wall -Werror -lmingw32 -lSDL2main -lSDL2
By the way I use clion 1.0.5

The problem is the flags, you mix compiler and linker flags. First of all this is problematic because the compiler flags aren't used when linking, and secondly because the GNU linker needs the libraries to come after the main source (or object) file on the command line, just like when you build manually.
You set the libraries by using the target_link_libraries command in your CMakeLists.txt file:
target_link_libraries(Sdltest mingw32 SDL2main SDL2)
Also, you're not building a C++ project, you're building a C project, so the flags variable should be CMAKE_C_FLAGS.
Finally, if you're wondering about the command and arguments that CMake uses when building, try making with VERBOSE set to non-zero, e.g.
make VERBOSE=1
I'm sure it's possible to add that argument to CLion.
PS.
If you want to enable more warnings, there are even more flags you could add, like -Wextra and -pedantic. Yes it might sometime give false positives, especially when including header files from external libraries, but I think it's better to have to many warnings when developing than to few.

Related

How to use LibFuzz on a C project that is not a library

I am trying to run libFuzz on a C project that usually compiles to an executable. The examples I found for libFuzz almost exclusively link with a library, i.e. a mylibary.a file. So I compiled the project with the normal Makefile, and combined the generated object files into a library with ar rcs a.o b.o etc.. Now I want to link this library file with the fuzzing target using clang++, but the linker is not able to find the implementation of the function I want to fuzz.
The command I use for linking inside the src directory of the project is
clang++ -Wall -fsanitize=fuzzer -Wno-cpp -Wpedantic -std=c++11 -O2 -g  -I/usr/include/libxml2 -g -O2 -rdynamic  -o fuzzing libmylib.a fuzztarget.cc -lcurl -lxml2 -I.
The error I get is "Undefined reference to function_xy()"
So the compiler finds the import of the function but not the implementation of it.
I am new to clang and generally building complex C projects so all help is greatly appreciated. Thank you!
I tried compiling the project with the included Makefile, then combining the generated object files into a .a library and finally linking the library with my fuzzing target.
The error you got is about linking, not the LibFuzzer. If you can compile and link your file without implementing function in LLVMFuzzerTestOneInput, then the fuzz-target should work: Include header in your code, call the function, compile file and link with libraries. Please check the order of include path, file, linked libraries. Be careful with the option of optimization (-O2), sometimes the fuzzer does not give crash with this option.

Why does linking with `mingw32` solve this compilation problem with SDL2?

I'm learning development using SDL2 with C on Windows and Mingw.
I tried the following command to compile my program:
gcc -IC:C:/msys64_new/mingw64/include/SDL2 *.c -o game.exe -g -Wall -Wno-unused -LC:/msys64_new/mingw64/lib -lSDL2main -lSDL2
It gave the error: Undefined reference to WinMain
Then I read that I should add -lmingw32 to the command:
gcc -IC:C:/msys64_new/mingw64/include/SDL2 *.c -o game.exe -g -Wall -Wno-unused -LC:/msys64_new/mingw64/lib -lmingw32 -lSDL2main -lSDL2
And now it works! My questions are:
Why does this solve the problem? What does linking with libmingw32.a do that solves this?
How does gcc find libmingw32.a? I don't seem to have such a file in the folder directed by -LC:/msys64_new/mingw64/lib.
libmingw32 is a part of mingw implementation of C runtime library, including e.g. crt0 and thread-local storage, stuff happening before your main is called. If you ask gcc to inform you what it does under the hood via gcc -v the_rest_of_your_build_command you'll see that it have -lmingw32 anyway in its linking command; it is possible to drop CRT (and CRT0) but that's for another question (and you'll need special handling since ordinary C programs expect CRT to be present).
There are some predefined paths linker search for libraries in. Historically for unix-like systems there are /lib, /usr/lib and so on. As mingw is mostly just ported gcc toolchain it inherits the same paths, just with its installation directory prefix (e.g. c:\mingw-w64\x86_64-w64-mingw32\lib. Check outout of ld --verbose output, specifically SEARCH_DIR.
Now why you need to specify -lmingw32 even though it is there anyway - the only reason is how ld linker resolves dependencies - left to right rule, basically. If one static library depends on another, it needs to be specified first in libraries list (but can be specified multiple times, it will not produce a conflict). In your case, #include <SDL.h> redefines your main function to SDL_main; that way your program don't have defined entry point anymore, but libSDL2main.a have one - simple main or WinMain that does minimal preparation and calls your SDL_main. So, you need to link with -lSDL2main, but by default -lmingw32 is appended last (resulting in e.g. -lSDL2main -lSDL2 -lmingw32), and linker don't search for definition of WinMain in SDL2main, and there is no WinMain in your .os, hence linking error. If you add -lmingw32 -lSDL2main -lSDL2, you have correct dependency chain - CRT0 depends on WinMain which implemented in SDL2main which also depends on SDL2. Default parameters will still add -lmingw32 at the tail, so you'll implicitly have it twice, but as I've said before you're allowed to do so.

Using a static library in C

I found a useful library on github for my project, after building this later I tried to use some predefined function on it. I couldn't compile my project because there is some header file missing like this one :
In file included from main.c:2:0:
ptask.h:11:19: fatal error: ptime.h: No such file or directory
I compiled my project using this command :
gcc main.c -L. -lptask
This is all the files in project folder :
libptask.a main.c ptask.h
This is the library content:
$ ar -t libptask.a
pbarrier.c.o
pmutex.c.o
ptask.c.o
ptime.c.o
rtmode.c.o
tstat.c.o
libdl.c.o
dle_timer.c.o
calibrate.c.o
Do I need to add all the headers of this files or just link the lib when compiling ?
Your main.c #include-s ptask.h which in turn #include-s ptime.h. Having compiled static libs alone is not enough (that's the linker's job), you still need to have all used header files (which is the compiler's job), both the ones you use and their dependencies, recursively applicable.
Normally you need to be sure that the header files are in your "include path", something that a lot of compilers define with -I as a command-line option. You'll need to include the source directory of that library, or if it has a make install option, then the place where they got installed.
regarding:
gcc main.c -L. -lptask
this is performing the compile step and the link step in one command.
It is also not enabling the warnings, which should always be enabled during the compile step.
Suggest something similar to the following to compile
gcc -Wall -Wextra -Wconversion -pedantic -std=gnu11 -g -c main.c -o main.o -I.
and when you have fixed all the warnings, then use something similar to the following to link
gcc main.o -o main -L. -lptask

Correctly setting linker flags using CMake

I have a project with C and ASM (AT&T) source files that needs a linker script. My CMakeLists.txt looks something like this:
cmake_minimum_required(VERSION 2.8.4)
project(proj C ASM-ATT)
file(GLOB SOURCE_FILES *.c *.S)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32 -Wall -g -fno-stack-protector -pedantic")
add_executable(proj ${SOURCE_FILES})
set_target_properties(proj PROPERTIES LINK_FLAGS "-T${proj_SOURCE_DIR}/link.ld -melf_i386")
Strangely enough, building with make VERBOSE=1 reveals the following:
[ 14%] Linking C executable proj
(...)
/usr/bin/cc -m32 -Wall -g -fno-stack-protector -pedantic -T/path/to/link.ld -melf_i386 (all object files)
cc: error: unrecognized command line option '-melf_i386'
It seems that CMake is trying to use /usr/bin/cc as a C linker. I have played around with this and tried several different options (including setting CMAKE_LINKER and CMAKE_EXE_LINK_OPTIONS).
Also note that CMakeCache.txt contains a line saying
CMAKE_LINKER:FILEPATH=/usr/bin/ld
so it obviously is aware of ld and is simply using the C compiler to link the executable.
Any help would be greatly appreciated!
CMake by default invokes the linker indirectly through the compiler executable. The template command for linking executables is set up in the variable CMAKE_LANG_LINK_EXECUTABLE.
To have the compiler pass the flags on to the linker, use -Wl upon setting LINK_FLAGS, i.e.:
set_target_properties(
proj PROPERTIES LINK_FLAGS "-Wl,-T${proj_SOURCE_DIR}/link.ld,-melf_i386")

cmake: altering the linker command

This probably very easy when you know how, but I don't :)
I'm trying to build some code that takes uses opengl/glut. I'm using the cygwin version of cmake opengl etc. The only reference I see to opengl/gult is in the CMakeLists.txt:
find_package(OpenGL REQUIRED)
find_package(GLU REQUIRED)
find_package(GLUT REQUIRED)
Everything works fine up till the linking stage, which ends with:
CMakeFiles/glview.dir/glview.c.o: In function `DrawGLScene': /cygdrive/C/code/libfreenect/examples/glview.c:88: undefined reference to `__imp__glutSwapBuffers#0'
CMakeFiles/glview.dir/glview.c.o: In function `keyPressed': /cygdrive/C/code/libfreenect/examples/glview.c:96: undefined reference to `__imp
etc.
After a git of googling I figured out this because cmake is feading the linker a -lglut flag, when it should be feading it a -lgut32 flag. By manually executing the linking command, I can get the program to build:
/usr/bin/gcc.exe -Wall -O3 -g -Wl,--enable-auto-import CMakeFiles/glview.dir/glview.c.o -o glview.exe -Wl,--out-implib,libglview.dll.a -Wl,--major-image-version,0,--minor-image-version,0 -L/cygdrive/C/code/libfreenect/lib ../lib/libfreenect.a -lGL -lGLU -lglut32 -lm -lpthread -lusb-1.0
But I can't figure out how to get cmake to generate this command for me so no manual steps are needed. Any ideas what I should be doing?
Cheers,
Rob
this is how to add libraries to link to:
target_link_libraries( ${TargetName} gut32 )
find_package only assures the package is found, no more.

Resources