Why does CMake repeat link libraries across link flags? - cmake

I'm using a third party project that provides dependencies to link against via a pkg-config file, which I pass to my target via target_link_libraries. The final result looks something like this example:
$ cat CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(main)
add_executable(main main.c)
target_link_libraries(
main
PRIVATE -lfoo
-Wl,--whole-archive
-lbar
-Wl,--no-whole-archive
-lfoo
-Wl,-Bdynamic
-lbaz)
Where main.c is a trivial C source file:
$ cat main.c
int main() { return 0; }
When I run CMake's configure step and inspect the generated compile commands, I see some libraries duplicated across link flags:
$ cmake -S . -B build -GNinja
$ ninja -C build -t commands
/usr/bin/cc -MD -MT CMakeFiles/main.dir/main.c.o -MF CMakeFiles/main.dir/main.c.o.d -o CMakeFiles/main.dir/main.c.o -c /home/ja/toy/main.c
: && /usr/bin/cc CMakeFiles/main.dir/main.c.o -o main -lfoo -Wl,--whole-archive -lbar -Wl,--no-whole-archive -lfoo -Wl,-Bdynamic -lbaz -lbar -lbaz && :
Clearly, -lbar was repeated across --no-whole-archive and -Bdynamic. Is this equivalent to the original target_link_libraries call? Why does CMake do this?
Additionally, I tried experimenting without the link flags, and noticed that CMake transforms -lfoo -lbar -lfoo -lbaz into -lfoo -lbar -lfoo -lbaz -lbar -lbaz. I suspect it might have something to do with the behavior described at LINK_INTERFACE_MULTIPLICITY but I do not understand the rationale behind doing this across link flags.
Edit: I'm using CMake version 3.23.0.

Related

CMake ninja custom target used as pre-build command modifies the files but ninja see the change of the depndecies during next build

I run some command before the actual build
add_custom_target("${PROJECT_BUILD_NUM_FILE}"
COMMAND ${PROJECT_BUILD_NUM_UPDATE} "-p" "-x" -f ${PROJECT_SOURCE_DIR}/${MAIN_PATH}/${BOARD_NAME}/${PROJECT_BUILD_NUM_FILE}
)
add_dependencies(${EXECUTABLE_NAME} "${PROJECT_BUILD_NUM_FILE}" )
When I build first time (the project was build before)
>------ Build started: Project: CMakeLists, Configuration: Debug ------
[1/1] cmd.exe /C "cd /D C:\Users\Piotr\git\gPIMS-EG\out\build\IoT-Debug && C:\Users\Piotr\git\gPIMS-EG\stm-libs\pc-exe\buildnum.exe -p -x -f C:/Users/Piotr/git/gPIMS-EG/src/EG/BuildID.h"
Build number file used:C:/Users/Piotr/git/gPIMS-EG/src/EG/BuildID.h
Build file updated: Build Number: 22 DateCode: 0x1d6d
Build succeeded.
BuildID.h file was modified and saved. Modification date is set correctly.
On the second build it behaves correctly
>------ Build started: Project: CMakeLists, Configuration: Debug ------
[1/4] cmd.exe /C "cd /D C:\Users\Piotr\git\gPIMS-EG\out\build\IoT-Debug && C:\Users\Piotr\git\gPIMS-EG\stm-libs\pc-exe\buildnum.exe -p -x -f C:/Users/Piotr/git/gPIMS-EG/src/EG/BuildID.h"
Build number file used:C:/Users/Piotr/git/gPIMS-EG/src/EG/BuildID.h
Build file updated: Build Number: 23 DateCode: 0x1d6d
[2/4] C:\PROGRA~2\Atollic\TRUEST~1.0\ARMTools\bin\AR097D~1.EXE -DALLOW_SOFTWARE_BKPTS=1 -DARM_MATH_CM4 -DBOOTLOADER_VERSION=1 -DCOMPILE_FOR_EG=1 -DDEBUGFILEWRITE=1 -DDEBUG_RUN_WITHOUT_CHECKS=1 -DFORCE_CUBE_USB -DHSE_VALUE=8000000UL -DSLOWSPIDEBUG=0 -DSTM32L -DSTM32L476xx -DSTM32L4xx -DUSE_EMBEDDED_PHY=1 -DUSE_FULL_ASSERT -DUSE_FULL_LL_DRIVER="" -DUSE_HAL_DRIVER -DUSE_SWOTRACE=1 -DUSE_USB_OTG_FS=1 -DUSE_USB_OTG_HS=1 -D_DEBUG=1 -D_GNU_SOURCE=1 -D__USE_SIMPLE_SWO=0 -I../../../src -I../../../src/EG -I../../../src/ZM -I../../../src/inc -I../../../stm-libs/inc -I../../../stm-libs/Drivers -I../../../stm-libs/Services -I../../../stm-libs/Services/Utils -I../../../stm-libs/RTOS/Source/include -I../../../stm-libs/RTOS/Source/portable/GCC/ARM_CM4F -I../../../stm-libs/Libraries/CMSIS/Include -I../../../stm-libs/Libraries/CMSIS/Device/ST/STM32L4xx/Include -I../../../stm-libs/Libraries/CryptoLib/Inc -I../../../stm-libs/Libraries/CryptoLib/Inc/RNG -I../../../stm-libs/drivers/USBD -I../../../stm-libs/Libraries/Middlewares/ST/STM32_USB_Device_Library/Core/Inc -I../../../stm-libs/Libraries/USB/Device/Class/CDC/Inc -I../../../stm-libs/Libraries/USB/Device/Class/MSC_HID/Inc -I../../../stm-libs/Libraries/USB/Device/Core/Inc -I../../../stm-libs/Libraries/lwip/ports/STM32F4x7 -I../../../stm-libs/Libraries/lwip/ports/STM32F4x7/arch -I../../../stm-libs/Libraries/lwip/src -I../../../stm-libs/Libraries/lwip/src/include -I../../../stm-libs/drivers/USBH -I../../../stm-libs/Libraries/USB/Host/Class/AUDIO/Inc -I../../../stm-libs/Libraries/USB/Host/Class/CDC/Inc -I../../../stm-libs/Libraries/USB/Host/Class/HID/Inc -I../../../stm-libs/Libraries/USB/Host/Class/MSC/Inc -I../../../stm-libs/Libraries/USB/Host/Class/MTP/Inc -I../../../stm-libs/Libraries/USB/Host/Core/Inc -I../../../stm-libs/Libraries/USB/Host/Class/Template/Inc -I../../../stm-libs/Libraries/lwip/ports/STM32F4x7/FreeRTOS -I../../../stm-libs/Libraries/misc -I../../../stm-libs/Libraries/FatFs/src -I../../../stm-libs/Libraries/littleFS -I../../../stm-libs/Apps -I../../../stm-libsApps/SeqZM -I../../../stm-libs/Libraries/libc_e -I../../../stm-libs/Libraries -I../../../stm-hal-l4/Inc/Legacy -I../../../stm-hal-l4/Inc -I../../../stm-libs/Apps/Other -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Og -g3 -T"C:/Users/Piotr/git/gPIMS-EG/src/EG/startup/EG.ld" -L"C:/Users/Piotr/git/gPIMS-EG/stm-libs/Libraries/CryptoLib" -lSTM32CryptographicV3.0.0_CM4_GCC_FPU -specs=nosys.specs -specs=nano.specs -Wl,-Map="EG.map" -static -Wl,-u,Reset_Handler -Wl,--gc-sections -Wl,--defsym=malloc_getpagesize_P=0x80 -Wl,--start-group -lc -lm -Wl,--end-group -ffunction-sections -fdata-sections -g -MD -MT CMakeFiles/GCEG-FW.dir/stm-libs/Apps/common/SC_Ver.c.obj -MF CMakeFiles\GCEG-FW.dir\stm-libs\Apps\common\SC_Ver.c.obj.d -o CMakeFiles/GCEG-FW.dir/stm-libs/Apps/common/SC_Ver.c.obj -c ../../../stm-libs/Apps/common/SC_Ver.c
In file included from ../../../stm-libs/Apps/common/SC_Ver.c:9:0:
C:\Users\Piotr\git\gPIMS-EG\stm-libs\Drivers\CAN-COB.h(267,2): warning GF07C7A44: #warning added to compile BP to change [-Wcpp]
#warning added to compile BP to change
^~~~~~~
[3/4] C:\PROGRA~2\Atollic\TRUEST~1.0\ARMTools\bin\AR097D~1.EXE -DALLOW_SOFTWARE_BKPTS=1 -DARM_MATH_CM4 -DBOOTLOADER_VERSION=1 -DCOMPILE_FOR_EG=1 -DDEBUGFILEWRITE=1 -DDEBUG_RUN_WITHOUT_CHECKS=1 -DFORCE_CUBE_USB -DHSE_VALUE=8000000UL -DSLOWSPIDEBUG=0 -DSTM32L -DSTM32L476xx -DSTM32L4xx -DUSE_EMBEDDED_PHY=1 -DUSE_FULL_ASSERT -DUSE_FULL_LL_DRIVER="" -DUSE_HAL_DRIVER -DUSE_SWOTRACE=1 -DUSE_USB_OTG_FS=1 -DUSE_USB_OTG_HS=1 -D_DEBUG=1 -D_GNU_SOURCE=1 -D__USE_SIMPLE_SWO=0 -I../../../src -I../../../src/EG -I../../../src/ZM -I../../../src/inc -I../../../stm-libs/inc -I../../../stm-libs/Drivers -I../../../stm-libs/Services -I../../../stm-libs/Services/Utils -I../../../stm-libs/RTOS/Source/include -I../../../stm-libs/RTOS/Source/portable/GCC/ARM_CM4F -I../../../stm-libs/Libraries/CMSIS/Include -I../../../stm-libs/Libraries/CMSIS/Device/ST/STM32L4xx/Include -I../../../stm-libs/Libraries/CryptoLib/Inc -I../../../stm-libs/Libraries/CryptoLib/Inc/RNG -I../../../stm-libs/drivers/USBD -I../../../stm-libs/Libraries/Middlewares/ST/STM32_USB_Device_Library/Core/Inc -I../../../stm-libs/Libraries/USB/Device/Class/CDC/Inc -I../../../stm-libs/Libraries/USB/Device/Class/MSC_HID/Inc -I../../../stm-libs/Libraries/USB/Device/Core/Inc -I../../../stm-libs/Libraries/lwip/ports/STM32F4x7 -I../../../stm-libs/Libraries/lwip/ports/STM32F4x7/arch -I../../../stm-libs/Libraries/lwip/src -I../../../stm-libs/Libraries/lwip/src/include -I../../../stm-libs/drivers/USBH -I../../../stm-libs/Libraries/USB/Host/Class/AUDIO/Inc -I../../../stm-libs/Libraries/USB/Host/Class/CDC/Inc -I../../../stm-libs/Libraries/USB/Host/Class/HID/Inc -I../../../stm-libs/Libraries/USB/Host/Class/MSC/Inc -I../../../stm-libs/Libraries/USB/Host/Class/MTP/Inc -I../../../stm-libs/Libraries/USB/Host/Core/Inc -I../../../stm-libs/Libraries/USB/Host/Class/Template/Inc -I../../../stm-libs/Libraries/lwip/ports/STM32F4x7/FreeRTOS -I../../../stm-libs/Libraries/misc -I../../../stm-libs/Libraries/FatFs/src -I../../../stm-libs/Libraries/littleFS -I../../../stm-libs/Apps -I../../../stm-libsApps/SeqZM -I../../../stm-libs/Libraries/libc_e -I../../../stm-libs/Libraries -I../../../stm-hal-l4/Inc/Legacy -I../../../stm-hal-l4/Inc -I../../../stm-libs/Apps/Other -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Og -g3 -T"C:/Users/Piotr/git/gPIMS-EG/src/EG/startup/EG.ld" -L"C:/Users/Piotr/git/gPIMS-EG/stm-libs/Libraries/CryptoLib" -lSTM32CryptographicV3.0.0_CM4_GCC_FPU -specs=nosys.specs -specs=nano.specs -Wl,-Map="EG.map" -static -Wl,-u,Reset_Handler -Wl,--gc-sections -Wl,--defsym=malloc_getpagesize_P=0x80 -Wl,--start-group -lc -lm -Wl,--end-group -ffunction-sections -fdata-sections -g -MD -MT CMakeFiles/GCEG-FW.dir/stm-libs/Apps/WaveMC3/waveMC3SeqGUI.c.obj -MF CMakeFiles\GCEG-FW.dir\stm-libs\Apps\WaveMC3\waveMC3SeqGUI.c.obj.d -o CMakeFiles/GCEG-FW.dir/stm-libs/Apps/WaveMC3/waveMC3SeqGUI.c.obj -c ../../../stm-libs/Apps/WaveMC3/waveMC3SeqGUI.c
In file included from ../../../stm-libs/Drivers/CAN-G3M.h:31:0,
from ../../../stm-libs/Drivers/ioCmd.h:12,
from ../../../stm-libs/Services/srvCmd.h:9,
from ../../../src/EG/../ZM/zmServices.h:10,
from ../../../src/EG/ourServices.h:12,
from ../../../stm-libs/Apps/WaveMC3/waveMC3SeqGUI.c:5:
C:\Users\Piotr\git\gPIMS-EG\stm-libs\Drivers\CAN-COB.h(267,2): warning GF07C7A44: #warning added to compile BP to change [-Wcpp]
#warning added to compile BP to change
^~~~~~~
[4/4] cmd.exe /C "cd . && C:\PROGRA~2\Atollic\TRUEST~1.0\ARMTools\bin\AR097D~1.EXE -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Og -g3 -T"C:/Users/Piotr/git/gPIMS-EG/src/EG/startup/EG.ld" -L"C:/Users/Piotr/git/gPIMS-EG/stm-libs/Libraries/CryptoLib" -lSTM32CryptographicV3.0.0_CM4_GCC_FPU -specs=nosys.specs -specs=nano.specs -Wl,-Map="EG.map" -static -Wl,-u,Reset_Handler -Wl,--gc-sections -Wl,--defsym=malloc_getpagesize_P=0x80 -Wl,--start-group -lc -lm -Wl,--end-group -ffunction-sections -fdata-sections -g #CMakeFiles\GCEG-FW.rsp -o GCEG-FW.elf && cmd.exe /C "cd /D C:\Users\Piotr\git\gPIMS-EG\out\build\IoT-Debug && "C:\Program Files (x86)\Atollic\TrueSTUDIO for STM32 9.3.0\ARMTools\bin\arm-atollic-eabi-objcopy.exe" GCEG-FW.elf --output-target=binary GCEG-FW.bin -j .isr_vector -j .VERSION_INFO -j .text -j .rodata -j .ARM.extab -j .ARM -j .preinit_array -j .init_array -j .fini_array -j .data -j .RAM_VectorTable -j .RAM_DATAfunctions -j .RAM_functions -v && "C:\Program Files (x86)\Atollic\TrueSTUDIO for STM32 9.3.0\ARMTools\bin\arm-atollic-eabi-size.exe" GCEG-FW.elf --format=Berkeley""
copy from `GCEG-FW.elf' [elf32-littlearm] to `GCEG-FW.bin' [binary]
text data bss dec hex filename
210428 36680 54020 301128 49848 GCEG-FW.elf
Build succeeded.
It looks like ninja is checking dependencies before the actual build starts and ignores meanwhile file changed. Is there any way to force cmake/ninja to recheck dependecies after custom target is build (ie prgram that thenges the build is run).
It looks like ninja is checking dependencies before the actual build starts and ignores meanwhile file change
Hey! Yes. Because DEPFILEs from C source files are generated at the same time as they are compiled, cmake has no way to know beforehand which file depends on which. It would have to do two passes - first to get dependencies and then to compile (which would be a nice feature, but actually hard to implement). It happens in one pass during compilation (-MD -MT flags), so cmake has no way of knowing that one file depends on that header. I also advise:
Do not modify files in your source tree. Keep all changes in BINARY_DIR.
Do not modify files. Generate new files. It's easier and generally, less state = less problems.
Try it such:
# Inside binary_dir
set(PROJECT_BUILD_NUM_FILE ${CMAKE_CURRENT_BINARY_DIR}/gen/buildid_gen.h)
# Add #include <buildid_gen.h> to your buildid.h
add_custom_command(
OUTPUT ${PROJECT_BUILD_NUM_FILE}
COMMAND ${PROJECT_BUILD_NUM_UPDATE} "-p" "-x" -f ${PROJECT_BUILD_NUM_FILE}
DEPENDS ${PROJECT_BUILD_NUM_UPDATE}
)
add_custom_target(buildid_gen
COMMENT "Yooohooo!"
DEPENDS ${PROJECT_BUILD_NUM_FILE}
)
add_executable(${EXECUTABLE_NAME} ${PROJECT_BUILD_NUM_FILE} ${some_other_sources})
target_add_include_directories(${EXECTABLE_NAME} PUBLIC
# add include directory, so that buildid_gen is found
${CMAKE_CURRENT_BINARY_DIR}/gen
)
# this *helps*
add_dependencies(${EXECUTABLE_NAME} buildid_gen)
Is there any way to force cmake/ninja to recheck dependecies after custom target is build (ie prgram that thenges the build is run).
The real proper way ™ would be to manually track all files that depend on the file (you could think of grep -l '#include <buildid_gen.h> to get the list files) and communicate to cmake the dependency relation:
add_source_file_properties(${sources_that_include_buildid_gen} PROPERTIES OBJECT_DEPENDS ${PROJECT_BUILD_NUM_FILE})
Tracking dependencies is easier if you use a runtime interface (ie. long get_build_id();) cause then only one .c file that implements the interface will depend on the generated file.
There are also some projects that are compiled in two passes because of such dependencies, you have to first cmake .. --target buildid_gen and then cmake .. --target actually_compile each time you compile.
Also maybe execute_process is more appropriate if the file is setup once per build.

Changed include path behaviour from CMake 2.8.x to 3.9.x

I have a fairly large cmake project that exhibits a compiler error when I use Makefiles generated by CMake 3.9.x:
Scanning dependencies of target client
[ 21%] Building C object
src/lib/client/CMakeFiles/client.dir/client.c.o
In file included from <command-line>:0:0:
/usr/include/stdc-predef.h:40:1: fatal error: compiler.h: No such file or directory
#endif
^
This works properly when using Makefiles generated by CMake 2.8.x. Digging in a bit, I can see that a change was made to the flags.make file generated by CMake between these two versions. The older version used to put -I (include) options in the C_FLAGS variable defined in that file:
# CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 2.8
# compile C with /usr/lib64/ccache/cc
C_FLAGS = -Wall -Wextra -Werror -Wformat=2 -Wundef -mcx16 -Werror-implicit-function-declaration -Wno-unused-parameter -D_GNU_SOURCE -include compiler.h -D__BUG_OUT_AUX=pd_trc_ftl -Wstrict-prototypes -Wdeclaration-after-statement -Wno-tautological-compare -g -I/.../src/lib/client ... -fPIC
C_DEFINES = -DBUILD_NUMBER=\"whatever\" -DBUILD_VERSION=\"1.66.0\" -DCOMMIT_HASH=\"f9bf1c93682f\" -DPDDEBUG -D_FILE_OFFSET_BITS=64
In later versions of CMake the -I options are broken out into their own C_INCLUDES variable:
# CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 3.9
# compile C with /usr/lib64/ccache/cc
C_FLAGS = -Wall -Wextra -Werror -Wformat=2 -Wundef -mcx16 -Werror-implicit-function-declaration -Wno-unused-parameter -D_GNU_SOURCE -include compiler.h -D__BUG_OUT_AUX=pd_trc_ftl -Wstrict-prototypes -Wdeclaration-after-statement -Wno-tautological-compare -g -fPIC
C_DEFINES = -DBUILD_NUMBER=\"whatever\" -DBUILD_VERSION=\"1.66.0\" -DCOMMIT_HASH=\"f9bf1c93682f\" -DPDDEBUG -D_FILE_OFFSET_BITS=64
C_INCLUDES = -I/.../src/lib/client ...
However, in both cases, the including file - build.make - uses only the $(C_DEFINES) $(C_FLAGS), omitting the $(C_INCLUDES) in the newer model:
...
# Include the compile flags for this target's objects.
include src/lib/client/CMakeFiles/client.dir/flags.make
src/lib/client/CMakeFiles/client.dir/client.c.o: src/lib/client/CMakeFiles/client.dir/flags.make
src/lib/client/CMakeFiles/client.dir/client.c.o: ../src/lib/client/client.c
#$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/.../cmake-build-debug/CMakeFiles --progress-num=$(CMAKE_PROGRESS_1) "Building C object src/lib/client/CMakeFiles/client.dir/client.c.o"
cd /.../cmake-build-debug/src/lib/client && /.../contrib/cc/cgcc.sh /.../cmake-build-debug /usr/lib64/ccache/cc sparse ON /.../client-project CMakeFiles/client.dir/client.c.o $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/client.dir/client.c.o -c /.../src/lib/client/client.c
...
Is this a bug in CMake 3.9.x? Has anyone else experienced anything like this when upgrading CMake?
I believe it's possible that we've always done something wrong in our CMakeLists.txt files that just happened to work in the older versions, but that when we upgraded to CMake 3.9.x, suddenly the problem is manifest. Hoping someone has had this issue and figured out what they did wrong.
Thanks in advance!

CMake on Cygwin with clang not creating expected dll.a

I'm building a shared library and an application using that lib on Cygwin. With GCC CMake creates a .dll.a to use when linking. Switching to clang I get
[ 34%] Built target xxx_shared
make[2]: *** No rule to make target 'src/libxxx.dll.a', needed by 'xxx.exe'. Stop.
Is this a bug in the clang CMake extension?
I'm using cmake --version 3.3.2
Yes, it seems to be a bug in CMake. Running make VERBOSE=1 reveals that with GCC:
/usr/bin/c++.exe -g -shared -Wl,--enable-auto-import -o XXX -Wl,-Bstatic -lm -Wl,-Bdynamic -lstdc++ -lcygwin -ladvapi32 -lshell32 -luser32 -lkernel32
while with clang:
/usr/bin/clang++ -fPIC -g -shared -o XXX -Wl,-Bstatic -lm -Wl,-Bdynamic -lstdc++ -lcygwin -ladvapi32 -lshell32 -luser32 -lkernel32
So it seems that somehow clang++ does not get the -Wl,--enable-auto-import flag. Manually running the corrected clang++ command correctly creates the expected .dll.a allowing the rest of the build to proceed as expected.
Haven't figured out why this happens yet, though. At this point I can't decipher CMakes platform extensions, which seems to set this for GCC.
Update: I've reported this here.

Cross-platform static-linking SDL2

I'm building an SDL2/C++ program that needs to be portable to Windows, Mac, and Linux machines which may not have SDL installed.
I've read that static linking is the solution, but I'm not very good with compiling and don't know how to static link.
My program relies only on SDL2, GLU, and OpenGL. I'm compiling C++ with either MinGW (on Windows 8.1) or gcc (on Ubuntu 14.04) -- both of these OS's have SDL installed natively.
Here is my current makefile, derived from a sample makefile given to me by a professor of mine:
# Executable/file name
EXE=experiment
# MinGW
ifeq "$(OS)" "Windows_NT"
CFLG=-O3 -Wall -DUSEGLEW
LIBS= -lSDL2 -lglu32 -lopengl32
CLEAN=del *.exe *.o *.a
else
# OSX
ifeq "$(shell uname)" "Darwin"
CFLG=-O3 -Wall -Wno-deprecated-declarations
LIBS=-framework SDL2 -framework OpenGL
# Linux\Unix\Solaris
else
CFLG=-O3 -Wall
LIBS= `sdl2-config --cflags --libs` -lGLU -lGL -lm
endif
# OSX\Linux\Unix\Solaris
CLEAN=rm -f $(EXE) *.o *.a
endif
# Dependencies
$(EXE).o: $(EXE).cpp FORCE
.c.o:
gcc -c -o $# $(CFLG) $<
.cpp.o:
g++ -std=c++11 -c -o $# $(CFLG) $<
# Link
$(EXE):$(EXE).o
g++ -std=c++11 -O3 -o $# $^ $(LIBS)
# Clean
clean:
$(CLEAN)
# Force
FORCE:
To link with static library you either specify path to library file
gcc -o out_bin your_object_files.o path/to/lib.a -lfoo
or ask linker to use static version with -Bstatic linker flag. Usually you'll want to reset linking back to dynamic for the rest of the libraries, e.g. for static SDL2 and GLU but dynamic GL:
gcc -o out_bin your_object_files -Wl,-Bstatic -lSDL2 -lGLU -Wl,-Bdynamic -lGL
That of course implies that static versions of libraries are present in library search path list (.a libs for gcc on all specified platforms, although MSVC uses .lib for static libraries).
However you usually don't really want to do that at all. It is common practice for software to either depend on some libs (widespread on linux, with packages and dependendices lists) or bring required libraries with it. You can just distribute SDL dynamic library with your program and load it with LD_LIBRARY_PATH or relative rpath.
Please also note that newer SDL2 implements dynamic loading of functions which provides a way to override SDL with user-specified dynamic library, even if linked statically.
It wasn't related directly to static linking. When static linking, I had to include all of SDL's dependency libraries. Turns out, having -mwindows causes console communication to fail.

Displaying a target's list of linked libraries in cmake

Is there a way to print a list the filenames for the libraries linked into a target via the target_link_libraries command
or even better, have all a target's dependencies copied to a specific folder?
get_target_property(OUT Target LINK_LIBRARIES)
message(STATUS ${OUT})
I realise this doesn't fully answer the question with regards doing it within cmake, but I faced a similar problem and thought I should share my solution.
First, in your source directory ("project"):
$ mkdir build && cd build
$ cmake ..
Then, use graphviz to create a dot file, as in this answer:
$ cmake --graphviz=graph.dot .
Then, strip out the dependencies from the graph for your target (let's call it "foo"):
$ sed -n 's/.*label="\(.*\)"\s.*/\1/p' graph.dot.foo > foo_dependencies.txt
Now, remove the clutter:
$ rm graph.dot*
Actually not(*).
However, you can use a cmake variable to collect the name of the libraries that you want to link (using the set( ... or the list(APPEND ... command), and then use this variable in your target_link_libraries command:
target_link_libraries(<targetname> ${YOUR_CMAKE_VARIABLE})
The same variable can also be used to create your copy commands (for example using this custom target)
(*) A similar question was asked here, and it got no definitive answer.
Well, all linked libraries to a given target TARGET are in the build.../CMakeFiles/TARGET.dir/link.txt.
For instance, TARGET=dirac.x,
.../build_intel17_mkl_i8/.less CMakeFiles/dirac.x.dir/link.txt
There will be a large number of linked libraries:
/cvmfs/it.gsi.de/compiler/intel/17.0/compilers_and_libraries_2017.4.196/linux/bin/intel64/ifort -Wl,-E -w -assume byterecl -g -traceback -DVAR_IFORT -i8 -w -assume byterecl -g -traceback -DVAR_IFORT -i8 -O3 -ip CMakeFiles/dirac.x.dir/src/main/main.F90.o -o dirac.x -L/tmp/milias-work/software/qch/dirac/devel_trunk/build_intel17_mkl_i8/external/lib -L/tmp/milias-work/software/qch/dirac/devel_trunk/build_intel17_mkl_i8/external/gen1int-build/external/lib -L/tmp/milias-work/software/qch/dirac/devel_trunk/build_intel17_mkl_i8/external/pelib-build/external/lib -Wl,-rpath,/tmp/milias-work/software/qch/dirac/devel_trunk/build_intel17_mkl_i8/external/lib:/tmp/milias-work/software/qch/dirac/devel_trunk/build_intel17_mkl_i8/external/gen1int-build/external/lib:/tmp/milias-work/software/qch/dirac/devel_trunk/build_intel17_mkl_i8/external/pelib-build/external/lib: libobjlib.dirac.x.a src/pelib/libpelib_interface.a external/lib/libstieltjes.a -limf -lsvml -lirng -lstdc++ -lm -lipgo -ldecimal -lstdc++ -lgcc -lgcc_s -lirc -lsvml -lc -lgcc -lgcc_s -lirc_s -ldl -lc external/pcmsolver/install/lib/libpcm.a /usr/lib/x86_64-linux-gnu/libz.so -limf -lsvml -lirng -lstdc++ -lm -lipgo -ldecimal -lstdc++ -lgcc -lgcc_s -lirc -lsvml -lc -lgcc -lgcc_s -lirc_s -ldl -lc /usr/lib/x86_64-linux-gnu/libz.so src/libxcfun_fortran_bindings.a external/xcfun-build/src/libxcfun.a external/lib/libpelib.a libgen1int_interface.a external/lib/libgen1int.a -Wl,--start-group /cvmfs/it.gsi.de/compiler/intel/17.0/compilers_and_libraries_2017.4.196/linux/mkl/lib/intel64/libmkl_lapack95_ilp64.a -lmkl_intel_ilp64 -qopenmp -Wl,--end-group -Wl,--start-group -lmkl_intel_ilp64 -lmkl_intel_thread -lmkl_core -lpthread /usr/lib/x86_64-linux-gnu/libm.so -qopenmp -Wl,--end-group external/pcmsolver/install/lib/libpcm.a external/xcfun-build/src/libxcfun.a external/lib/libpelib.a external/lib/libgen1int.a /cvmfs/it.gsi.de/compiler/intel/17.0/compilers_and_libraries_2017.4.196/linux/mkl/lib/intel64/libmkl_lapack95_ilp64.a -lmkl_intel_ilp64 -lmkl_intel_thread -lmkl_core -lpthread /usr/lib/x86_64-linux-gnu/libm.so -lirng -ldecimal -lstdc++