CMake to produce -L<path> -l<lib> link flags for static libraries - cmake

I'm using CMake 2.8 in order to build an application based on MQX OS (using CodeWarrior).
The CMake project basically builds a set of static libraries (let's say LIB1 and LIB2).
I then reference these libraries in the final executable cmake rule:
target_add_executable(X ${some_sources})
target_link_libraries(X LIB1 LIB2)
My problem is that some symbols are defined in more that one library.
Thus, a link command like:
mwldarm <args> -o <output> <objects> /path/to1/libLIB1.a /path/to2/libLIB2.a
would lead to multiple definition of symbols error.
Instead, I would like CMake to generate a link command like:
mwldarm <args> -o <output> <objects> -L/path/to1 -L/path/to2 -lLIB -lLIB2
Question: How to get the following variables from CMAKE?
Libraries directories flags (ex: -L/path/to1 -L/path/to2)
Libraries link flags (ex: -lLIB -lLIB2)
I've read stuff concerning RPATH but it seems to concern shared libraries only. Am I right?
Thanks for advance.
I do appreciate.

It seems that policy CMP0003 may be what you need.
To use it add the following line near the beginning of your CMakeLists.txt:
CMAKE_POLICY( SET CMP0003 OLD )
Another possibility is to directly set the dependencies and search path, however it's not the cleanest way. Assuming you libraries are called liba.a and libb.a, then:
LINK_DIRECTORIES( ${paths_to_search_for} )
TARGET_ADD_EXECUTABLE(X ${some_sources} )
ADD_DEPENDENCIES(X LIB1 LIB2)
TARGET_LINK_LIBRARIES(X a b )
Note that in this case a and b are not cmake targets, therefore a little machinery is needed to correctly set the dependencies.

Part of the design of CMake is that it links with full paths. Why is that a problem?
Toggling the behavior with the policy is not the correct approach.
http://www.cmake.org/gitweb?p=cmake.git;a=commitdiff;h=cd4fa896b

I think CMP0003 is used to switch on/off the function of adding searching path automatically as described in the official document
Libraries linked via full path no longer produce linker search paths.
rather than about replacing the path name with -l.
When linking a library, if the library is a target CMake known, CMake always replaces related -L and -l options with the library's path name. This may not be a problem for linking static libraries. But for a executable to link a shared library, it's may be a problem. Then I found a hacking method, code like below, to solve the problem linking a shread library using -L and `-l' rather than absolute path.
# Find out the link.txt
set(LINK_TXT "${CMAKE_BINARY_DIR}/${ToLinkLib}/CMakeFiles/${ToLinkLIb}.dir/link.txt")
# Add the searching path into link command
add_custom_command(TARGET ${YourTarget} PRE_BUILD
COMMAND sed ARGS -ie "\"s;[[:blank:]]-l; -L${LIBRARY_OUTPUT_PATH} -l;\"" ${LINK_TXT}
DEPENDS ${LINK_TXT}
COMMENT "Hacking CMake: edit __link.txt__ to use -l instead of path to link internal library ...")
# NOTE: Dont't missing the `-l'.
target_link_libraries(${YourTarget} -l${ToLinkLib})
Of course, this is just a hacking so may not be working well with all versions of CMake.
UPDATED: why linking a shared library may be a problem?
When I run a executable cross compiled for android, which linking a shared library built by the same CMake scripts, I've encounter a problem of linking failed. After I used the above hacking method to get a new version, I can run my executable with a command like below
$ LD_LIBRARY_PATH=. ./the_exe opts

Related

CMake TARGET_RUNTIME_DLLS is empty

I have git cloned, built (with MSVC for both Debug and Release) and then installed wxWidgets:
cmake -B build wxWidgets
cmake --build build --config <CONFIG>
cmake --install build --prefix my_install --config <CONFIG>
with <CONFIG> = Debug and <CONFIG> = Release.
Then I used the following CMake script to link against it, as suggested by the wiki:
cmake_minimum_required(VERSION 3.16)
project(Test)
add_executable(Test WIN32 Main.cpp)
# wxWidgets
SET(wxWidgets_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../thirdparty/my_install)
find_package(wxWidgets COMPONENTS core base REQUIRED)
include(${wxWidgets_USE_FILE})
target_link_libraries(Test PRIVATE ${wxWidgets_LIBRARIES})
# Copy runtime DLLs to the directory of the executable.
add_custom_command(TARGET Test POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Runtime Dlls: $<TARGET_RUNTIME_DLLS:Test>"
)
My goal is to automatically copy the DLLs into the directory of the built executable, so that they can be found at runtime. For that I'm using the TARGET_RUNTIME_DLLS generator expression (follwing the sample code in the docs). In the code above, I only print out the expression at build time for testing purposes. The problem is that it is empty.
The approach worked for me before when installing and linking SDL, but SDL provides package configuration files which create imported targets, defining the DLL location(s) via IMPORTED_LOCATION_RELEASE or IMPORTED_LOCATION_DEBUG. For wxWidgets one is apparently supposed to use the FindwxWidgets.cmake script shipped with CMake, which sadly doesn't define the produced binaries. Maybe that's why TARGET_RUNTIME_DLLS isn't populated.
Does anyone know, either how to get TARGET_RUNTIME_DLLS filled or how to obtain the list of built wxWidgets DLLs for the current configuration (Release/Debug) post build copying?
Thanks a lot in advance!
I am dealing with a similar problem.
First sanity checks:
You have to work on windows platform otherwise this feature does not
work.
Your Cmake is 3.21 or above
Next comes fuzzy part. I think the library that you are trying to include have to be a Shared Imported library and you have to set a set_target_properties for IMPORTED_IMPLIB which is a path to a .lib file of sort (dll import library, I think it is called) So you have to make sure that it is all set in the package library that you trying to link with your executable.
If you have those dll avaiable and you just want to use them and not actually build them then you can write your own cmake script that will do just what I said above. Then you can include that cmake file in your project and then link against your app.
Note: I also work on similar issue right now and what I just said have not been working very reliably. I got some dlls to be copied and some do not.
Edit:
Cmake docs give a more detailed explanation on how this library setting should look like if you use find_package feature.
Found here: https://cmake.org/cmake/help/latest/command/add_library.html#imported-libraries
An UNKNOWN library type is typically only used in the implementation
of Find Modules. It allows the path to an imported library (often
found using the find_library() command) to be used without having to
know what type of library it is. This is especially useful on Windows
where a static library and a DLL's import library both have the same
file extension.

CMake add linker options after .obj files

Cross compiling an executable for an embedded system with CMake requires me to manually add link options to link libc, libgcc and whatnot. However using target_link_options for that results in a linker call where all those additional link options are added in front of all the object files generated from my actual code. I believe that this is the wrong linking order and it causes "duplicate symbol errors" whenever I try to overwrite weak symbols from the standard library (e.g. __cxa_pure_virtual).
Here is an exemplar of the output I get from the linking stage
"/usr/bin/ld.lld"
--gc-sections
/usr/arm-none-eabi/lib/crt0.o
/usr/lib/gcc/arm-none-eabi/10.1.0/thumb/v7e-m+fp/hard/crti.o
/usr/lib/gcc/arm-none-eabi/10.1.0/thumb/v7e-m+fp/hard/crtbegin.o
/usr/lib/gcc/arm-none-eabi/10.1.0/thumb/v7e-m+fp/hard/crtn.o
/usr/lib/gcc/arm-none-eabi/10.1.0/thumb/v7e-m+fp/hard/crtend.o
--start-group -lstdc++_nano -lm -lgcc -lc_nano --end-group
my.obj ///< Shoudln't object files and application libs be linked first?
libmylib.a
-Bstatic
-L/usr/lib/clang/10.0.0/lib/baremetal
-L/usr/arm-none-eabi/lib/thumb/v7e-m+fp/hard/
-L/usr/lib/gcc/arm-none-eabi/10.1.0/thumb/v7e-m+fp/hard/
-T ldscript.ld
-o myelf
Is there any way to solve this in CMake?
target_link_options specifies options to the linker - and typically options are specified before anything else. Use target_link_libraries to link with libraries.

Creating a library in CMake depending on source files not available when generating build files

I have a CMake configuration file building two libraries:
a third-party library (here called ThirdPartyLib) containing a real-time OS / board support package from a supplier. It is built outside CMake using the autotools toolchain.
an extended version of the former library (here called ExtendedThirdPartyLib)
Unfortunately, some source code that I need (various tools) are not built in the ordinary build script for (1). Since I don't want to mess with the suppliers build script I want to add another library (2), building the missing files and thus extending the library from the supplier.
I want to able to do something like this in CMakeFiles.txt:
cmake_minimum_required(VERSION 3.2)
project(bsp)
include(ExternalProject)
ExternalProject_Add(
ThirdPartyLib
URL <http://some.url/bsp.tar.bz2
BUILD_COMMAND make -C ../external/ThirdPartyLib/src
)
set_target_properties(ThirdPartyLib PROPERTIES EXCLUDE_FROM_ALL TRUE)
add_library(ExtendedThirdPartyLib
${CMAKE_CURRENT_BINARY_DIR}/some/path/missing_file1.c
${CMAKE_CURRENT_BINARY_DIR}/some/path/missing_file2.c
)
add_dependencies(ExtendedThirdPartyLib ThirdPartyLib)
target_include_directories(ExtendedThirdPartyLib PUBLIC
${CMAKE_CURRENT_BINARY_DIR}/some/path/include
)
target_link_libraries(ExtendedThirdPartyLib ThirdPartyLib)
The problem here is that the path to missing_file1.c and missing_file2.c are not valid when CMake is generating the build files (they are extracted from the tarball from the supplier). CMake exits with an error output saying: "Cannot find source file".
Is there a neat way to make this work? I.e. is it possible to convince CMake that certain non-existant input files will exist when building of the library begins? Or is there any other recommended way to solve this issue?
(I have temporary made local copies of the files I need to build from the suppliers tarball, but that is of course not a good solution. If those files are changed in future versions of the suppliers package and I forget to overwrite my local copies it could be a horrible mess...
Another "solution" would be to create a small makefile outside CMake and use another ExternalProject_Add in the CMakeFiles.txt somehow. But that's not a good solution either, e.g. if compile and linker flags are modified I need to remember to change the makefile too.)
Personally, I dislike the ExternalProject_Add command, because it does way too many things for my taste, but I've digressed.
What if you do something like this, where bar is simulating your ExtendedThirdPartyLib target, since it depends on generated files
cmake_minimum_required(VERSION 3.11)
project(lol C)
set(SOURCES lol.c) # only this file exists
add_library(lol ${SOURCES})
set(FOO_FILES "foo1.c" "foo2.c")
add_custom_command(OUTPUT ${FOO_FILES}
COMMAND ${CMAKE_COMMAND} -E touch ${FOO_FILES}
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
COMMENT "Creating ${FOO_FILES}"
VERBATIM)
add_custom_target(foo DEPENDS ${FOO_FILES})
add_library(bar ${FOO_FILES})
add_dependencies(bar foo)
target_link_libraries(lol bar)
The whole approach hinges on the fact that the method, where produced/generated files are procured, is explicitly defined via the custom command and associated custom target.
You should modify the custom command to extract the required files (e.g. could even call some external script) from the tarball (which might require downloading with curl or something similar).

Retrieve all link flags in CMake

In CMake, is it possible to programmatically retrieve the complete list of linker flags that will be used for a given target? The only way I can see to do this is to inspect the link.txt file in the target's CMakeFiles directory. Not ideal.
The use case that I'm interested in is to collect the data to include in something like a pkg-config file. I'm writing a library, and it includes a couple executable utilities that use the library. Building the executables (especially when the library is build statically) requires a non-trivial link line to link to my library and its dependencies. So I'd like to write out the link line necessary for building these executables to a data file included with the package such that other clients can know how to link.
As #Tsyvarev has commented there is no build-in command or property "to programmatically retrieve the complete list of linker flags" in CMake.
But inspired by your hint "so I'd like to write out the link line necessary for building these executables to a data file" I think I found a feasible solution (at least for makefile generators).
And if I understand your request correctly, we are not talking about simple verbose outputs like you get with e.g. CMAKE_VERBOSE_MAKEFILE, which would still need you to copy things manually.
So taking the following into account:
You need to run the generator first to get the real link line
CMake allows you to invent any linker language by name
You can define the link line with CMAKE_>LANG<_LINK_EXECUTABLE using variables and expansion rules
I came up with adding an LinkLine executable using my ECHO "linker" with the single purpose to create a link line file of my choosing:
set(CMAKE_ECHO_STANDARD_LIBRARIES ${CMAKE_CXX_STANDARD_LIBRARIES})
set(CMAKE_ECHO_FLAGS ${CMAKE_CXX_FLAGS})
set(CMAKE_ECHO_LINK_FLAGS ${CMAKE_CXX_LINK_FLAGS})
set(CMAKE_ECHO_IMPLICIT_LINK_DIRECTORIES ${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES})
set(
CMAKE_ECHO_LINK_EXECUTABLE
"<CMAKE_COMMAND> -E echo \"<FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>\" > <TARGET>"
)
add_executable(LinkLine "")
target_link_libraries(LinkLine MyLibraryTarget)
set_target_properties(
LinkLine
PROPERTIES
LINKER_LANGUAGE ECHO
SUFFIX ".txt"
)
The nice thing about this approach is, that the output of my LinkLine target can be used as any other "officially generated" executable output (e.g. in install() commands or post-build steps with generator expressions):
add_custom_command(
TARGET LinkLine
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:LinkLine> PackageCfg/$<TARGET_FILE_NAME:LinkLine>
)
References
Recursive list of LINK_LIBRARIES in CMake
add_custom_command is not generating a target

Building SDL2_image as a CMake external project

I've been trying to create a CMake-based build-system for a project that is supposed to use SDL2_image library. I do not want to force user to install any libraries to the system to be able to build the project, so I took advantage of the CMake's ability to download and build dependencies (freetype, SDL2 and SDL2_image) from source code as External Projects.
Everything is fine with freetype and SDL2 (which both include CMakeLists.txt files out of the box), but I've ran out of ideas how to make it work for SDL2_image. CMake's external projects support custom configuration and building settings which I used in different variants with no success.
The CMake file itself can be found here, but the problematic part is this:
# SDL_image library
ExternalProject_Add(sdl2_image_project
URL https://www.libsdl.org/projects/SDL_image/release/SDL2_image-2.0.0.tar.gz
DEPENDS sdl2_project
PREFIX ${LIBS_DIR}/SDL2_image
CONFIGURE_COMMAND LDFLAGS=-L${SDL2_BIN} CFLAGS=-I${SDL2_SRC}/include SDL2_CONFIG=${SDL2_BIN}/sdl2-config <SOURCE_DIR>/configure --prefix=<INSTALL_DIR> --enable-shared=no
BUILD_COMMAND make
INSTALL_COMMAND ""
)
An error occurs while building sdl2_image_project. Some trivial research discovered that the error is generated by the undefined references to parts of libdl. Here is a tiny part of the hole error:
libtool: link: gcc -I/home/snikitin/_src/img_glypher/libs/SDL2/src/sdl2_project/include -I/usr/local/include/SDL2 -D_REENTRANT -o showimage showimage.o -Wl,-rpath -Wl,/usr/local/lib -pthread -L/home/snikitin/_src/img_glypher/libs/SDL2/src/sdl2_project-build ./.libs/libSDL2_image.a -L/usr/local/lib -lSDL2 -pthread
/home/snikitin/_src/img_glypher/libs/SDL2/src/sdl2_project-build/libSDL2.a(SDL_dynapi.c.o): In function `get_sdlapi_entry':
/home/snikitin/_src/img_glypher/libs/SDL2/src/sdl2_project/src/dynapi/SDL_dynapi.c:227: undefined reference to `dlopen'
I think the problem takes place due to the fact that linker tries to create a shared version of SDL2_image library while linking it to a static libSDL2.a. The thing is - if this is right - SDL2 building step creates both static and shared versions of itself so one would assume that linker would use libSDL2-2.0.so instead (I do not actually need a shared library - just the static one, but I do not know how to prevent the build system from trying to create it apart from passing --enable-shared=no to SDL2_image configure script, which does not help in this case).
After a lot of googling I've discovered that the possible source of the problem is that sdl2-config (which is called to get some flags for compiler during SDL_image building) may be called with wrong arguments and produces wrong cflags which confuse everything else. But I'm not sure that is the case and also I do not know how to influence sdl2_config call from CMake (configure --help does not seem to unveil any useful options for this situation).
I am running Ubuntu 14.04 x64 if it matters in any way. Would appreciate any advice!
Looks like you need to link some libraries like m and dl. It can be fixed by providing
custom sdl2-config file. Copy sdl2-config from extracted archive and substitute --libs result:
--libs)
echo -L${exec_prefix}/lib -Wl,-rpath,${libdir} -pthread -lSDL2 -lm -ldl
;;
Note that order is important (that's why just modifying LIBS not works for me).
Now this file can be used in your ExternalProject_Add command instead of SDL2_CONFIG=${SDL2_BIN}/sdl2-config:
...
... CFLAGS=-I${SDL2_SRC}/include SDL2_CONFIG=${CMAKE_CURRENT_LIST_DIR}/sdl2-config <SOURCE_DIR>/configure
...