CMake: Link a library to library - cmake

I have a problem with cmake. I have, lets say, CMakeLists1 which has a subdirectory where CMakeLists2 is.
In CMakeLists2 my target is a static library. And I want to link it to external library.
I've made it just like that:
link_directories ("path_to_library")
add_library (project2 ${sources})
target_link_libraries (project2 "name_of_external_lib")
Then, I want to use a class from this project2 in my project1. I've made it that way:
add_executable (project1 ${sources})
target_link_libraries (project1 project2)
But that doesn't work at all. First of all, project2 didn't link to external library. Just for checking, I've added this library through vs10 project properties, and the sizes were different. And the second thing, somehow project1 sees that external library (it is in library dependencies of this project) and of course can't find it.
What is the problem?

I think it's CMake's default behavior to not link project2 to the external library,
but to link both libraries to the executable.
From the book "Mastering CMake".
Since static libraries do not link to the libraries on which they depend, it is
important for CMake to keep track of the libraries so they can be specified on the
link line of the executable being created.
You could try to use an absolute path in your CMakeLists2:
add_library (project2 ${sources})
target_link_libraries (project2 "path to ext lib"/"name of ext lib")
or you could add
link_directories ("path_to_library")
to the CMakeLists file of project1.
If you really want to do something like in Visual Studio, you could probably use the command given in this answer to build a custom_command in CMake.
It probably would look something like this (I didn't test it).
set(EXT_LIB "path_to_library/name_of_external_lib")
set(BIG_LIB "path_to_big_lib/name_of_big_lib")
add_library (project2 ${sources})
get_property(PROJ2_LOC TARGET project2 PROPERTY LOCATION)
add_custom_command(OUTPUT ${BIG_LIB}
DEPENDS ${EXT_LIB} project2
COMMAND "lib.exe /OUT:${BIG_LIB} ${EXT_LIB} ${PROJ2_LOC} )
Then you could link your executable with ${BIG_LIB}.
Some things you have to consider:
Maybe you have to use LOCATION_CONFIG (CMake docs, I found the get_property command in this answer )
link.exe has to be in your path
watch the scope of the BIG_LIB variable if you want to use it in an other CMakeLists.txt

I'm guessing the trouble will likely be that *name_of_external_lib* is not correct so it can't find it.
I would go with:
find_library(
LIB_I_NEED name_of_external_lib
HINTS "path_to_library"
)
if(${LIB_I_NEED} STREQUAL "LIB_I_NEED-NOTFOUND")
message(FATAL_ERROR "Couldn't find the 'external_lib' library)
endif()
message(STATUS "Found 'external_lib' at: ${LIB_I_NEED}")
add_library (project2 ${sources})
target_link_libraries (project2 ${LIB_I_NEED})
If that doesn't help, have a quick read of the example in the cmake docs:
http://www.cmake.org/cmake/help/v2.8.8/cmake.html#command:target_link_libraries
One thing it mentions in there is:
While one repetition is usually sufficient, pathological object file
and symbol arrangements can require more. One may handle such cases by
manually repeating the component in the last target_link_libraries
call
So I would say the other thing to try might be in project2:
set(PROJECT_2_LIBS project2 "name_of_external_lib" PARENT_SCOPE)
then in the exe:
target_link_libraries (project1 ${PROJECT_2_LIBS})
That will have the 'external_lib' linkage repeated in the two places and give you more chance of it working ;)

Related

How to force the CMake that write a file after executing each line instead of creating it at last?

I'm writing a CMakeList for big projects with many libraries. this CMakeList appends these small projects with add_subdirectory like:
add_subdirectory(a)
add_subdirectory(b)
Each subdirectory has multiple static libraries. libraries of b directories depend on libraries of a directories. I implementing the function for finding libraries like bellow:
if (TARGET ${FINDING_NAME})
get_target_property(BINARY_DIR ${FINDING_NAME} BINARY_DIR}
find_library(FINDING_LIBRARY_PATH
NAMES ${LIBRARY_NAME}
HINTS ${BINARY_DIR})
list(APPEND ${DEPENDENCIES_LIST} ${FINDING_LIBRARY_PATH})
else()
find_library(FINDING_LIBRARY_PATH
NAMES ${LIBRARY_NAME})
list(APPEND ${DEPENDENCIES_LIST} ${FINDING_LIBRARY_PATH})
endif()
unfortunately, When executing the Cmake for the first time all Dependencies find in /usr/local/lib or /usr/lib. I expect to find for example project_dir/Release/a/... but when I execute the Cmake for the second time, the Dependencies are found in project_dir/Release/a/....
I think Cmake generates the .a file at the last but I need these .a at the middle(when calling add_library()).
Do you have an idea to solve this problem?
Just remove your find_library code and link with the libraries you need to:
target_link_libraries(thetarget a)
If the target a exists, the target will be used for linking.
If the library is installed to /usr/local/lib and /usr/lib, then -la will make the compiler find the library liba.a from the standard ld.so.conf search paths.
If the library is not installed and the target does not exist, linker will inform you of a missing library.
find_library is for searching a library from a very specific path, no need to use it if you are searching for a library in compiler standard search paths (and you are not handling cases when the library is not found). Linker is for finding libraries, no need to use CMake for it.

CMake build and install shared library from subdirectory before building main directory

Here is my source code structure:
cd my_git_repo/
CMakeLists.txt
src/
main.cpp
mylibrary/
a.hpp
b.hpp
a.cpp
b.cpp
CMakeLists.txt
Root CMakeLists.txt:
cmake_minimum_required(VERSION 3.9)
project(myexe CXX)
add_subdirectory(src/mylibrary)
find_library(mylib NAMES mylibrary.so PATHS "./src/mylibrary/mylibrary.so")
add_executable(myexe src/main.cpp)
target_link_libraries(myexe ${mylib})
mylibrary/CMakeLists.txt is very simple. It builds a shared library and installs them.
Ideally, mylibrary target should be built and installed before myexe is built. But this doesn't happen. mylibrary is built followed by myexe. Installation happens later. Because of this, find_library fails. pkg_check_modules() works for other shared libraries but fails here because of the same reason.
I appreciate your help.
Edit:
This question differs from the duplicate because the answers posted to that question seem to be statically linking the library target_link_libraries(game engine). I want to dynamically link the .so library.
The idea in CMake is to build modules and then link them together.
You haven't shared the CMakeLists.txt for my library, so we cannot tell what it is doing. However, assuming that it is something like:
ADD_LIBRARY(mylibrary
file1.cpp
file2.cpp
)
Since you specified that you want mylibrary to always be linked as shared, you need to tell CMake that as well by either setting BUILD_SHARED_LIBS TO ON or by specifying SHARED in add_library:
ADD_LIBRARY(mylibrary SHARED
file1.cpp
file2.cpp
)
This is your library module. We will keep it simple for now and not worry about packing the library archive and installation here.
Now, back to your main CMakeLists.txt and how to make myexe consume it. Since you have already add_subdirectory(src/mylibrary), CMake knows about mylibrary. So simply link it using the module name. There is no need to find_library as you have already defined the module.
add_executable(myexe src/main.cpp)
target_link_libraries(myexe mylibrary)
This should suffice.
Do note, however, this is a very basic example to explain to you how CMake is designed to work. If you aren't building the library, and it is already installed, you would call find_library. Modern CMake is a bit more sophisticated and uses generator expressions, so be sure to read up on that as you progress to more complex projects.

Directing cmake to link against shared object with debug postfix (_d)

I've got a cmake project that pretty much looks like this:
cmake_minimum_required(VERSION 3.0)
SET(CMAKE_DEBUG_POSTFIX "_d")
include_directories(../TransfunctionerProject)
include_directories(../TransmogrifierProject)
set(Libraries
ContinuumTransfunctioner
Transmogrifier
)
set(SourceFiles
Wrapper.cpp
Logger.cpp
)
add_library(Frobnigator SHARED ${SourceFiles})
add_library(FrobnigatorStatic STATIC ${SourceFiles})
set_target_properties(FrobnigatorStatic PROPERTIES OUTPUT_NAME Frobnigator)
target_link_libraries(Frobnigator ${Libraries})
Where ContinuumTransfunctioner and Transmogrifier projects include the debug postfix directive SET(CMAKE_DEBUG_POSTFIX "_d") so that libContinuumTransfunctioner_d.so and libTransmogrifier_d.so both exist.
The problem is that the current project appears to be linking against the static library without the _d suffix and complains:
/usr/bin/ld: cannot find -lContinuumTransfunctioner
The Libraries that you pass into the target_link_libraries call are interpreted as filenames, not as target names.
This is the unfortunate fallback for that call in CMake: If you pass a random string to it, that cannot be interpreted in a meaningful way, CMake will always assume it to be plain library name. Sometimes this is just what you want, but the name has to be an exact match for an existing library. The whole debug postfix magic will be lost here.
What you might have wanted to do was to pass a library target name instead. This will trigger a much smarter handling of the dependency and would solve your problem. However, that only works if the library is a known target in the context of the target_link_libraries call. You can easily check this as follows:
if(TARGET ContinuumTransfunctioner)
message("Library target name")
else()
message("Plain library name")
endif()
target_link_libraries(Frobnigator ContinuumTransfunctioner)
So how do you get to the target name case? This depends on how your build is structured. If the library is being built as part of your CMake run, simply make sure that the corresponding add_library call is performed from a subdirectory that is pulled in via add_subdirectory from the file that performs the target_link_libraries call.
If the library in question is an external dependency, you need to build an imported target that carries all the relevant information where to find the library files (including any potential debug postfixes). This can be a bit cumbersome to do manually, so if you can, you might want to use CMake's packaging mechanism to generate this automatically as part of the library's build process.
Here's the solution, courtesy of the good people on the cmake mailing list:
# Note:
# $<$<CONFIG:Debug>:_d> is called a generator expression.
# It outputs _d if the build is debug.
#
set(Libraries
ContinuumTransfunctioner$<$<CONFIG:Debug>:_d>
Transmogrifier$<$<CONFIG:Debug>:_d>
)

Specifying libraries for cmake to link to from command line

I have a huge project managed with CMake and this project has hundreds of components each of them having own source files and each of them linking to a list of libraries, specified with target_link_libraries(${project} some_libraries, some_other_libraries)
Now, what I am aiming for is that:
Without actually modifying any of the CMakeLists.txt I want ALL the projects's target executable to link to some specific libraries.
Is there a way of achieving this? Since this is a one time trial, I don't want to manually hunt down all the CMakeLists.txt files and modify them (yes, this is the other alternative). Just a note, I compile the entire project from command line, using cmake (no cmake gui).
This is kind of a hack, but for a C++ project, you can use CMAKE_CXX_STANDARD_LIBRARIES. For a C project, I think you would use CMAKE_C_STANDARD_LIRBARIES.
Example for C++ that links to libbar and libfoo:
cmake ... -DCMAKE_CXX_STANDARD_LIBRARIES="-lbar -lfoo"
See the documentation here:
https://cmake.org/cmake/help/v3.6/variable/CMAKE_LANG_STANDARD_LIBRARIES.html
This won't be available for older versions of CMake; it was added some time after version 3.0.
This is a dirty, dirty hack, so please only use it for testing.
You can actually overload the add_executable command by defining a function of the same name. Do this close to the top of the top-level CMakeLists.txt:
function (add_executable name)
message("Added executable: " ${name})
_add_executable(${name} ${ARGN})
target_link_libraries(${name$} your_additional_lib)
endfunction()
Note that _add_executable is an internal CMake name that may break in future CMake versions. As of now (version 3.0) it seems to work with all versions though.
You can overload add_library the same way if required.
For more fine-grained control over what is linked, instead of calling target_link_libraries you can also mess with the LINK_LIBRARIES and INTERFACE_LINK_LIBRARIES target properties directly.

CMake basic usage

I'm trying to build my library with CMake. I'm working on CMakeLists.txt .
I want to be able to do the following:
I have a directories called
include
src
Then inside of these there is
Agui folder.
And in that folder are the sub folders of the library.
So far from what I've gathered:
I'll need to do:
set(AGUI_SOURCES
src/Agui/Rectangle.cpp
src/Agui/xxx.cpp (and so on)
)
Then I think need to do:
include_directories(./include)
And then I'm not quite sure.
I know that add_library will be involved but I'm not sure how.
The thing is, I want to create 2 options: DLL, or static.
If it is DLL, then AGUI_BUILD_DLL must be defined.
So based on this information:
Am I on the right track?
How do I create the options
What do I put in add_library
How do I add the preprocessor AGUI_BUILD_DLL if the user wants the DLL version?
If any or all of these could be answered I would greatly appreciate it.
Thanks
I would recommend taking a look at the CMake tutorial which covers adding executables, libraries, system introspection etc. The cmake command also self documents, so on the command line entering,
cmake --help-command add_library
would give you the documentation for the add_library command. You could use the --help-commands to get a full listing of all CMake command documentation. So you can use the option command to add an option for building shared or static, and use the add_definitions command to add a preprocessor definition.
For example,
option(BUILD_SHARED "Build shared libraries" OFF)
if(BUILD_SHARED)
add_definitions(-DAGUI_BUILD_DLL)
add_library(agui SHARED ${AGUI_SOURCES})
else()
add_library(agui STATIC ${AGUI_SOURCES})
endif()
You should note targetName_EXPORTS will be defined when building the library, and so can be used in the declspec logic. This is done by CMake, and is also useful when using visibility support in GCC on Unix systems.
Maybe , do not know :)
OPTION(AGUI_BUILD_DLL "Build agui DLL" OFF)
somewhere near the start of CMakeLists.txt. You may want to use ON instead of OFF - depends on whether you want DLL build to de default.
3,4.
if(AGUI_BUILD_DLL)
add_library(agui SHARED ${AGUI_SOURCES})
set_target_properties(agui PROPERTIES DEFINE_SYMBOL "AGUI_BUILD_DLL")
else()
add_library(agui STATIC ${AGUI_SOURCES})
endif()