Link with self-compiled static libraries with cmake - c++

I try to write some tests for project. If I need some project files I write include_directories statement and all will be included. In case of need of some manually compiled static libraries I try to set target_link_libraries.
If I set absolute path then all links ok, but for task I need another way to link another libraries, because the relative path to libraries gives undefined references.
In this case everything works fine:
target_link_libraries(ConsoleDumperTest GTest::GTest GTest::Main PocoFoundation PocoUtil PocoNet ${YAML_LIBRARIES})
target_link_libraries(ConsoleDumperTest /home/yrusinov/projects/build-fleetd-2-Desktop-dbg/protocols/libprotocols.a)
target_link_libraries(ConsoleDumperTest /home/yrusinov/projects/build-fleetd-2-Desktop-dbg/consumers/libconsumers.a)
target_link_libraries(ConsoleDumperTest /home/yrusinov/projects/build-fleetd-2-Desktop-dbg/consumers/Console/libconsole.a)
but if I do:
target_link_libraries(ConsoleDumperTest GTest::GTest GTest::Main PocoFoundation PocoUtil PocoNet ${YAML_LIBRARIES})
target_link_libraries(ConsoleDumperTest ../../../protocols/libprotocols.a)
target_link_libraries(ConsoleDumperTest ../../../consumers/libconsumers.a)
target_link_libraries(ConsoleDumperTest ../../../consumers/Console/libconsole.a)
I receive undefined references, despite of libraries contains in there directories. Which way I have to set path to link libraries?

According to documentation, target_link_libraries is not expected to work with relative paths: you should use either an absolute path, or a library name.
By knowing relative path, it is easy to construct absolute path in CMake. E.g., assuming you know relative path to the current source directory (the directory contained currently executed CMakeLists.txt), use CMAKE_CURRENT_SOURCE_DIR variable:
target_link_libraries(ConsoleDumperTest
${CMAKE_CURRENT_SOURCE_DIR}/../../../protocols/libprotocols.a
)

CMake's link_directories(...) command provides this:
link_directories(directory1 directory2 ...)
Specify the paths in which the linker should search for libraries. The command will apply only to targets created after it is called. Relative paths given to this command are interpreted as relative to the current source directory, see CMP0015.
Note also that, if these library dependencies are defined within the same CMake project, using add_library(target_name ...), you may specify the target name instead of the binary name within target_link_libraries.

Related

Force CMake target_link_libraries to fail when adding nonexistent target

CMake has an irritating default (I presume, I see nothing magical in my CMake config, but I could be wrong since I know very little about CMake) behavior that he silently ignores when you add a target to your project even if that target does not exist, for example:
project(StackOverflow)
// another CMakeLists.txt
project (Stuff)
target_link_libraries(Stuff
PUBLIC StackOverlow )
Is there a way to force CMake to check that all projects you link in target_link_libraries must exist?
It is possible for CMake to fail if you link ALIAS targets. For example
In first CMakeLists.txt
add_library(StackOverflow STATIC lib.cpp)
add_library(StackOverflow::StackOverflow ALIAS StackOverflow)
In second CMakeLists.txt
target_link_libraries(Stuff PUBLIC StackOverflow::StackOverflow)
CMake will fail with an error if StackOverflow::StackOverflow is not defined.
https://cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html#alias-targets
In CMake, you do not link projects to other projects. Instead, you link targets to other targets.
CMake targets are only created via a few commands (such as add_library, add_executable, and add_custom_target). The project command does not create a CMake target, it merely declares a project.
Furthermore, the target_link_libraries() command accepts the following arguments after the scoping keyword:
A library target name
A full path to a library file
A plain library name
A link flag
A generator expression
A debug, optimized, or general keyword
It does not accept project names, although if you put a project name, it will instead look for a CMake target or library file on your system with that name.
To get to the root of what I believe you're asking: If you provide link-item name to target_link_libraries() that does not match an existing target, the command will simply search for a library file of that name instead.
To check if a target exists before trying to link it, you can do:
if (TARGET StackOverflow)
target_link_libraries(Stuff PUBLIC StackOverflow)
endif()
I suggest reading through the linked target_link_libraries() documentation if you want more details about what this command does.

How to link external C++ library to my project on Mac OSX [duplicate]

I have 2 folders "inc" and "lib" in my project which have headers and static libs respectively. How do I tell cmake to use those 2 directories for include and linking respectively?
The simplest way of doing this would be to add
include_directories(${CMAKE_SOURCE_DIR}/inc)
link_directories(${CMAKE_SOURCE_DIR}/lib)
add_executable(foo ${FOO_SRCS})
target_link_libraries(foo bar) # libbar.so is found in ${CMAKE_SOURCE_DIR}/lib
The modern CMake version that doesn't add the -I and -L flags to every compiler invocation would be to use imported libraries:
add_library(bar SHARED IMPORTED) # or STATIC instead of SHARED
set_target_properties(bar PROPERTIES
IMPORTED_LOCATION "${CMAKE_SOURCE_DIR}/lib/libbar.so"
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/include/libbar"
)
set(FOO_SRCS "foo.cpp")
add_executable(foo ${FOO_SRCS})
target_link_libraries(foo bar) # also adds the required include path
If setting the INTERFACE_INCLUDE_DIRECTORIES doesn't add the path, older versions of CMake also allow you to use target_include_directories(bar PUBLIC /path/to/include). However, this no longer works with CMake 3.6 or newer.
You had better use find_library command instead of link_directories. Concretely speaking there are two ways:
designate the path within the command
find_library(NAMES gtest PATHS path1 path2 ... pathN)
set the variable CMAKE_LIBRARY_PATH
set(CMAKE_LIBRARY_PATH path1 path2)
find_library(NAMES gtest)
the reason is as flowings:
Note This command is rarely necessary and should be avoided where there are other choices. Prefer to pass full absolute paths to
libraries where possible, since this ensures the correct library will
always be linked. The find_library() command provides the full path,
which can generally be used directly in calls to
target_link_libraries(). Situations where a library search path may be
needed include: Project generators like Xcode where the user can
switch target architecture at build time, but a full path to a library
cannot be used because it only provides one architecture (i.e. it is
not a universal binary).
Libraries may themselves have other private library dependencies that
expect to be found via RPATH mechanisms, but some linkers are not able
to fully decode those paths (e.g. due to the presence of things like
$ORIGIN).
If a library search path must be provided, prefer to localize the
effect where possible by using the target_link_directories() command
rather than link_directories(). The target-specific command can also
control how the search directories propagate to other dependent
targets.
might fail working with link_directories, then add each static library like following:
target_link_libraries(foo /path_to_static_library/libbar.a)

How to set relative paths with respect to upper subdirectories in CMakeList.txt?

I am modifying a CMakeLists.txt to compile a library with dependencies. I'm confused how to provide relative paths to locations which are in subdirectories above CMAKE_CURRENT_LIST_DIR. Normally, I would use CMAKE_CURRENT_LIST_DIR to create relative paths, or use the absolute path. The latter isn't an option here.
Here's my situation:
Using CMakeLists.txt, it currently cannot find the other libraries (here, FIRST, SECOND, and THIRD) via
find_package(FIRST REQUIRED)
find_package(SECOND REQUIRED)
So, I would like to set the include/lib paths via:
FIRST_INCLUDE_DIR=
FIRST_LIBRARY=
SECOND_INCLUDE_DIR=
SECOND_LIBRARY=
Currently, for the full directory of the listfile currently being processed, the following
message("${CMAKE_CURRENT_LIST_DIR}")
outputs
/home/travis/build/repohandle/libraryname/00_pkg_src/libraryname/src/package
However, the locations for FIRST and SECOND are here:
/home/travis/build/repohandle/libraryname/00_pkg_src/libraryname/src/first
/home/travis/build/repohandle/libraryname/00_pkg_src/libraryname/src/second
How could I link to /src/first and /src/second using a relative path?
Something like:
FIRST_INCLUDE_DIR="${SOME_LOCATION}/src/first/include"
FIRST_LIBRARY="${SOME_LOCATION}/src/first/"
SECOND_INCLUDE_DIR="${SOME_LOCATION}/src/second/include"
SECOND_LIBRARY="${SOME_LOCATION}/src/second/include"

Set C++ object file output location with CMake

I would like to use CMake for a project, but I have the following two requirements:
The final output of the project should be a set of object files (*.o).
The location of the object files is important. I want to select which directory the files are outputted.
Does CMake support this type of behavior? If so, how? Can I do it with move commands after the object file is build?
First create an object library.
Now the problem is that:
Object libraries cannot be imported, exported, installed, or linked.
http://www.cmake.org/cmake/help/v2.8.11/cmake.html#command:add_library
I would try to use the install(DIRECTORY ...).
Using the options:
DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} #Probably you have to check more precisely where the object files are built
DESTINATION #it's something relative to DESTDIR, if set, or CMAKE_INSTALL_PREFIX otherwise
FILES_MATCHING
PATTERN "*.o"
A flaw of this solution will be in the output directory name, that will be basically decided by cmake, I wonder if anything can be done in that respect.

cmake - find_library - custom library location

I'm currently trying to get CMake running for my project (on windows). I want to use a custom location where all libraries are installed. To inform CMake about that path I tried to do that:
set(CMAKE_PREFIX_PATH D:/develop/cmake/libs)
But when I try to find the library with
find_library(CURL_LIBRARY NAMES curl curllib libcurl_imp curllib_static)
CMake can't find it.
When I set my prefix path to
set(CMAKE_PREFIX_PATH D:/develop/cmake/libs/curl)
... the library is located.
So my question is:
How can I configure CMake properly to work with a directory structore at a custom location which looks like that:
D:/develop/cmake/libs/
-> libA
-> include
-> lib
-> libB
-> include
-> lib
-> ...
-> include
-> lib
In "include" lie the public headers and in "lib" are the compiled libraries.
edit:
The current workaround for me is, to do this before i search for libraries:
set(CUSTOM_LIBRARY_PATH D:/develop/cmake/libs)
file(GLOB sub-dir ${CUSTOM_LIBRARY_PATH}/*)
foreach(dir ${sub-dir})
if(IS_DIRECTORY ${dir})
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH};${dir})
endif()
endforeach()
But that way the default module for boost wont find it until it because the directory structore of boost is a bit different.
boost -> include -> boost-1_50 -> *.hpp
When I move the content if "boost-1_50" to "include" the library can be found but that way it's not possible to handle multiple versions right?
The simplest solution may be to add HINTS to each find_* request.
For example:
find_library(CURL_LIBRARY
NAMES curl curllib libcurl_imp curllib_static
HINTS "${CMAKE_PREFIX_PATH}/curl/lib"
)
For Boost I would strongly recommend using the FindBoost standard module and setting the BOOST_DIR variable to point to your Boost libraries.
I saw that two people put that question to their favorites so I will try to answer the solution which works for me:
Instead of using find modules I'm writing configuration files for all libraries which are installed. Those files are extremly simple and can also be used to set non-standard variables. CMake will (at least on windows) search for those configuration files in
CMAKE_PREFIX_PATH/<<package_name>>-<<version>>/<<package_name>>-config.cmake
(which can be set through an environment variable).
So for example the boost configuration is in the path
CMAKE_PREFIX_PATH/boost-1_50/boost-config.cmake
In that configuration you can set variables. My config file for boost looks like that:
set(boost_INCLUDE_DIRS ${boost_DIR}/include)
set(boost_LIBRARY_DIR ${boost_DIR}/lib)
foreach(component ${boost_FIND_COMPONENTS})
set(boost_LIBRARIES ${boost_LIBRARIES} debug ${boost_LIBRARY_DIR}/libboost_${component}-vc110-mt-gd-1_50.lib)
set(boost_LIBRARIES ${boost_LIBRARIES} optimized ${boost_LIBRARY_DIR}/libboost_${component}-vc110-mt-1_50.lib)
endforeach()
add_definitions( -D_WIN32_WINNT=0x0501 )
Pretty straight forward + it's possible to shrink the size of the config files even more when you write some helper functions. The only issue I have with this setup is that I havn't found a way to give config files a priority over find modules - so you need to remove the find modules.
Hope this this is helpful for other people.
Use CMAKE_PREFIX_PATH by adding multiple paths (separated by semicolons and no white spaces). You can set it as an environmental variable to avoid having absolute paths in your cmake configuration files
Notice that cmake will look for config file in any of the following folders
where is any of the path in CMAKE_PREFIX_PATH and name is the name of the library you are looking for
<prefix>/ (W)
<prefix>/(cmake|CMake)/ (W)
<prefix>/<name>*/ (W)
<prefix>/<name>*/(cmake|CMake)/ (W)
<prefix>/(lib/<arch>|lib|share)/cmake/<name>*/ (U)
<prefix>/(lib/<arch>|lib|share)/<name>*/ (U)
<prefix>/(lib/<arch>|lib|share)/<name>*/(cmake|CMake)/ (U)
In your case you need to add to CMAKE_PREFIX_PATH the following two paths:
D:/develop/cmake/libs/libA;D:/develop/cmake/libB
There is no way to automatically set CMAKE_PREFIX_PATH in a way you want. I see following ways to solve this problem:
Put all libraries files in the same dir. That is, include/ would contain headers for all libs, lib/ - binaries, etc. FYI, this is common layout for most UNIX-like systems.
Set global environment variable CMAKE_PREFIX_PATH to D:/develop/cmake/libs/libA;D:/develop/cmake/libs/libB;.... When you run CMake, it would aautomatically pick up this env var and populate it's own CMAKE_PREFIX_PATH.
Write a wrapper .bat script, which would call cmake command with -D CMAKE_PREFIX_PATH=... argument.
You have one extra level of nesting.
CMAKE will search under $CMAKE_PREFIX_PATH/include for headers and $CMAKE_PREFIX_PATH/libs for libraries.
From CMAKE documentation:
For each path in the CMAKE_PREFIX_PATH list, CMake will check
"PATH/include" and "PATH" when FIND_PATH() is called, "PATH/bin" and
"PATH" when FIND_PROGRAM() is called, and "PATH/lib and "PATH" when
FIND_LIBRARY() is called.
I've encountered a similar scenario. I solved it by adding in this following code just before find_library():
set(CMAKE_PREFIX_PATH /the/custom/path/to/your/lib/)
then it can find the library location.