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

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.

Related

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.

CMAKE - makefile target for a library

I'm currently changing the build system on my project, from gnu makefiles to cmake (that generate makefiles).
My project generates several libraries (.lib), and several executables (.exe).
Currently i generate the makefiles using the following command :
cmake -G "Unix Makefiles" .. -DCMAKE_BUILD_TYPE=Debug
The generated makefiles contain an all target, as well as a target for every executable (compiled as such with the add_executable cmake directive), so i can compile a subset of the project (which saves a lot of time) : make executable_1; make executable_2 and so on.
However, there is no target for the libraries (compiled as such with the add_library cmake directive) so i cannot do make library_1 for example. I want to do this because it would save a lot of time.
I tried to add a dummy executable in the library's cmake, and link the library to this executable (which only contains a main without actually using library_1's code).
add_library(library_1 test.cpp)
add_executable(dummy_exe dummy_main.cpp)
target_link_library(dummy_exe library_1)
It does add a target for dummy_exe but does not build the library because it does not actually need to link any of the library_1's code.
This was a workaround attempt anyway, and i'd rather just call make library_1 after all. Is there any way to add a makefile target for a library using cmake ?
As answered by w-m and Fred, CMAKE indeed create a target for libraries in the Makefile.
I was trying to build the library with the cmake subproject name of the library instead of the library name.
make help was indeed of big help to find this issue, as it lists everything that can be built.

How to force CMake to link to system library instead of target with same name

I have a library with the same name as a system library. Most of the executables in my project link to my own library but one executable needs to link to the system library. CMake is generating a g++ command line linking to ../foo/libfoo.a and I need it to link to -lfoo instead.
I have a structure something like this:
/CMakeLists.txt
add_directory(foo)
add_directory(program)
/foo/CMakeLists.txt
add_library(foo foo.cpp)
/program/CMakeLists.txt
add_executable(program program.cpp)
target_link_libraries(program foo)
One solution would be to change the name of my library so it doesn't conflict but I'd rather not do that because reasons. I'm looking for some CMake magic to let me tell it to use the system library.
I'd rather not do that because reasons.
I can see your hands are tied here :) so I would recommend "finding" the system library using find_library and linking to that. If successful, find_library will yield the absolute path to the library, and if you use that variable in your subsequent target_link_libraries call, it should leave no room for ambiguity.
So in "/program/CMakeLists.txt", something like:
find_library(SystemFoo NAMES foo)
add_executable(program program.cpp)
target_link_libraries(program ${SystemFoo})
You may even want to include a few of the NO_xxx_PATH args (e.g. NO_CMAKE_ENVIRONMENT_PATH and/or NO_CMAKE_PATH) to the find_library call to reduce the number of locations CMake will search for the library.

How would I build and link an external library using CMake?

To start off, I should say that I've seen the answers on questions that were similar to mine, yet none of them seem to make sense to me. Here goes:
Say I have the following simple CMakeLists:
cmake_minimum_required (VERSION 2.8)
project (Example)
add_executable (Example Main.cpp)
I would then like to link a library that already has its own CMakeLists (for example, glfw) against Example. Of course, this brings into question how to properly set up the build order.
How would I go about doing this?
First let me describe what to do for GLFW. See the notes below for variations.
Build GLFW. As the official GLFW head's CMake support is currently broken, use this shaxbee fork:
git clone https://github.com/shaxbee/glfw.git
cmake -Hglfw -Bbuild/glfw -DCMAKE_INSTALL_PREFIX=inst -DCMAKE_BUILD_TYPE=Release
cmake --build build/glfw --target install --config Release
This install step installs inst/lib/cmake/glfw3/glfw3Config.cmake, the glfw3 config-module which will be used by client projects to find GLFW.
Your project should look like this:
cmake_minimum_required(VERSION 2.8)
project(Example)
find_package(glfw3 REQUIRED)
add_executable(Example Main.cpp)
target_link_libraries(Example glfw3)
The find_package command finds the glfw3Config.cmake which creates an IMPORTED library, a CMake target, which incorporates all the information needed to use GLFW in your project.
The target_link_libraries command tells CMake not only to link to GLFW but to use its include directories and compile flags, too.
Configure your project with -DCMAKE_PREFIX_PATH=inst (use full path if necessary)
Note: Other config-modules or find-modules may not provide IMPORTED targets. See the actual config or find-module for help. They usually provide <PACKAGE>_INCLUDE_DIRS and <PACKAGE>_LIBRARIES variables which should be added to the appropriate settings of your target:
target_include_directories(mytarget ${ZLIB_INCLUDE_DIRS})
or
include_directories(${ZLIB_INCLUDE_DIRS})
Same for target_link_libraries / link_libraries.
Build the external dependency first.
add a function call to find your external library. That can either be FindGLFW.cmake with find_package if you can find that or write it yourself using find_library et al. More information about including external libraries can be found in the CMake wiki
Add the includes and libraries to your Example executable.
This is how CMake should be used, I don't see why is not answered in the sources in the Internet.

CMake: Link a library to library

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 ;)