Cmake 'find_libraries', NAMES keyword not working - c++

First time user here so pleasy be gentle.
I have problem with linking libraries using cmake.
I'am working on part of the bigger project. Each part has its own build system, but can use libraries from other parts. Eample project tree:
+-- Project
| +-- Part1
| +-- Lib1
| +-- libLib1.a
| +-- Lib2
| +-- libLib2.a
| +-- Part2
| +-- Lib3
| +-- libLib3.a
| +-- Lib4
| +-- libLib4.a
| +-- MyPart
| +-- Lib5
| +-- libLib5.a
| +-- Lib1.cpp
| +-- CMakeLists.txt
| +-- main.cpp
| +-- CMakeLists.txt
I try to link my part MyPart, with libraries Lib1, Lib2, Lib4, Lib5.
With Lib5 there is no problem as it is build with the same cmake tree.
But how to link outside libraries?
I choose to use find_library to obtain path to each of the other needed library, for example:
find_library(LIB1_LIBRARY
NAMES Lib1
PATH ../Part1/Lib1/)
And then use target_link_libraries. Unfortunetly as a result of find_library i get LIB1_LIBRARY-NOTFOUND.
But if keyword NAMES is to be removed, all start working as expected.
What is wrong here? And also is there better strategy for linking libraries from outside of my build system tree.
thank you in advance

Related

Tradeof between CMAKE_BINARY_DIR and PROJECT_BINARY_DIR when setting submodule targets' output directories

I'm working on a library which will be used by another project. The main project uses a couple of libraries linked as git submodules. Inside the library project used as a submodule, I can set the LIBRARY_OUTPUT_DIRECTORY and the ARCHIVE_OUTPUT_DIRECTORY in two different ways.
In option A the targets are built and saved to their own subdirectories using the ${PROJECT_BINARY_DIR}/lib, but in option B all targets are built and saved to the ${CMAKE_BINARY_DIR}/lib directory.
This could also be extended to binaries built by the submodules. Thus, which of the two options will scale better / is normally used as best-practice?
OPTION A
CMakeLists.txt
# Set target properties
set_target_properties(${PROJECT_NAME}_lib_shared PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
set_target_properties(${PROJECT_NAME}_lib_static PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib/static)
Folder Structure
.
+-- build
| +-- bin
| +-- MainProject
| +-- test
| +-- lib
| +-- SubModuleA
| +-- SubModuleA_lib_shared.a
| +-- static
| +-- SubModuleA_lib_static.so
| +-- SubModuleB
| +-- SubModuleB_lib_shared.a
| +-- static
| +-- SubModuleB_lib_static.so
+-- lib
| +-- SubModuleA
| | +-- CMakeLists.txt
| +--- SubModuleB
| | +-- CMakeLists.txt
+-- inc
| +-- foo.h
+-- src
| +-- foo.cpp
| +-- main.cpp
| +-- CMakeLists.txt
+-- test
| +-- test.cpp
| +-- CMakeLists.txt
+-- CMakeLists.txt
OPTION B
CMakeLists.txt
# Set target properties
set_target_properties(${PROJECT_NAME}_lib_shared PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set_target_properties(${PROJECT_NAME}_lib_static PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib/static)
Folder Structure
.
+-- build
| +-- bin
| +-- MainProject
| +-- test
| +-- lib
| +-- SubModuleA_lib_shared.a
| +-- SubModuleB_lib_shared.a
| +-- static
| +-- SubModuleA_lib_static.so
+-- SubModuleB_lib_static.so
+-- lib
| +-- SubModuleA
| | +-- CMakeLists.txt
| +--- SubModuleB
| | +-- CMakeLists.txt
+-- inc
| +-- foo.h
+-- src
| +-- foo.cpp
| +-- main.cpp
| +-- CMakeLists.txt
+-- test
| +-- test.cpp
| +-- CMakeLists.txt
+-- CMakeLists.txt
Unless there is a good reason you shouldn't set the output directory for your targets in the library project at all. If consumers link to the CMake targets provided by the library project then they usually don't even need to know where exactly these libraries will be located, and even if they do they have access to the location through target-dependent generator-expressions.
Moreover, even if you do have a good reason (e.g. because you'd like to archive the build-artifacts in a CI build and don't use CPack to generate proper packages yet), you still shouldn't force your setup upon consumers. If you allow consumers to easily overwrite the defaults they can e.g. use that mechanism to ensure the shared libraries will be located next to a binary their project builds, which is required on Windows to run the executable without having to manually modify the PATH to include all directories where the dependencies are located, i.e. consumers can ensure that the executable can be run from the build tree by changing the default output directory of your library target.
You thus shouldn't set the target properties, and instead set the defaults for these properties by setting
if (NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib/static")
endif()
if (NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
endif()
if (NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
endif()
to make it more convenient for consumers to change the output location of all targets all at once without having to set the properties manually for each target again.
Whether you use ${PROJECT_BINARY_DIR} or ${CMAKE_BINARY_DIR} then is largely irrelevant, but I personally prefer to use ${PROJECT_BINARY_DIR} because it ensures there will be no conflicts, even if two subprojects chose the same name for their target (e.g. several targets might define an executable that is just called tests).

CMake Build a target as part of project and independently

I am attempting to write CMakeLists.txt for a platform. The platform has multiple projects which share some libraries and have their own executables. I wish to be able to build each project as a whole, as well as individual executables from within the project.
out-of-source root build works fine:
mkdir root-build && cd root-build && cmake ../root
out-of-source executable build does not work:
mkdir ui-build && cd ui-build && cmake ../root/project1/ui
My current directory structure is as follows:
root/
+-- CMakeListst.txt
+-- lib/
+-- CMakeLists.txt
+-- sharedLib1/
+-- CMakeLists.txt
+-- sharedLIb2/
+-- CMakeLists.txt
+-- project1/
+-- CMakeLists.txt
+-- ui/
+-- CMakeLists.txt
+-- executable1/
+-- CMakeLists.txt
+-- shared/
+-- CMakeLists.txt
+-- project2/
+-- CMakeLists.txt
+-- executable/
+-- CMakeLists.txt
My current project structure builds all targets and libraries as part of the project great, but I can't figure out how to build an executable in isolation.
The main cmake file for a project is root/project*/CMakeLists.txt. This file INCLUDES root/CMakeLists.txt, which does some setup common to all projects (e.g setting CMAKE_MODULE_PATH and find_package for third-party libraries). The project cmake file also calls add_subdirectory for each of it's executables and add_subdirectory(../lib libs).
This allows executables to link against any of the targets defined in the root/lib subdirectory. If I then try to build the executable independently of the project, CMake will not be able to find the target the executable needs to link against. Is there an elegant solution / pattern that would allow this? One way I thought of was to just add_subdirectory(../../ root) from the ui/CMakeLists.txt, with something resembling header guards to prevent an infinite add_subdirectory loop.
Use make executable1 (for example) to build individual targets.

Wildcards with autoconf and automake

I have an C++ project in Eclipse that uses Autoconf and Automake. My (simplified) project structure is the following:
+-- Makefile.am
+-- configure.ac
+-- src/
| +-- 4Bench.cpp
| | +-- Makefile.am
| | +-- folder1/
| | | +-- ...
| | +-- folder2/
| | | +-- ...
| | +-- folder3/
| | | +-- ...
+-- include/
| +-- ...
The folder src/ will contain multiple binaries (4Bench.cpp is one of them) that will use the .cpp files located in folder1, folder2, etc. All the header files are located in include/. My src/Makefile.am looks as follows:
bin_PROGRAMS=4Bench
4Bench_SOURCES=4Bench.cpp folder1/file11.cpp folder2/file21.cpp ...
4Bench_CPPFLAGS=-I$(top_srcdir)/include
AM_CPPFLAGS=$(BOOST_CPPFLAGS)
AM_LDFLAGS=$(BOOST_LDFLAGS)
4Bench_LDADD=$(BOOST_PROGRAM_OPTIONS_LIB)
Since I expect to have many files in the subfolders of src/, I want to use wildcards to have something like:
4Bench_SOURCES=4Bench.cpp $(wildcard folder1/*.cpp) $(wildcard folder2/*.cpp) $(wildcard folder3/*.cpp)
Unfortunately this leads to a bunch of errors of the form "undefined reference", that is, the compiler cannot find the implementation of the classes in the .cpp files. Enumerating every single file that is required by the binary works. For further reference I provide both the ./configure.ac and ./Makefile.am files.
./configure.ac
AC_PREREQ(2.59)
AC_INIT(4Bench, 0.1)
AC_CANONICAL_SYSTEM
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects -Wno-portability])
AC_PROG_CXX
AC_CONFIG_MACRO_DIR([m4])
AX_CXX_COMPILE_STDCXX_11
AX_BOOST_BASE([1.32],,[AC_MSG_ERROR([4Bench needs Boost, but it was not found in your system])])
AX_BOOST_PROGRAM_OPTIONS
AX_BOOST_UNIT_TEST_FRAMEWORK
AC_CONFIG_FILES(Makefile src/Makefile test/Makefile)
AC_OUTPUT
./Makefile.am
SUBDIRS=src test
ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4
EXTRA_DIST = bootstrap
Any ideas about how to solve the issue? I am using Linux Mint 18 with g++ 5.4.0, autoconf 2.69 and GNU automake 1.15. Thanks for your attention & help!
Any ideas about how to solve the issue?
You can't do that with the current implementation of automake. This is a feature.

cmake: how to separately compile production code and test code

I read this brilliant tutorial about how to integrate Google Test with CMake. The outline of the project there looks like this:
+-- CMakeLists.txt
+-- main
| +-- CMakeLists
| +-- main.cpp
|
+-- test
| +-- CMakeLists.txt
| +-- testfoo
| +-- CMakeLists.txt
| +-- main.cpp
| +-- testfoo.h
| +-- testfoo.cpp
| +-- mockbar.h
|
+-- libfoo
| +-- CMakeLists.txt
| +-- foo.h
| +-- foo.cpp
|
+-- libbar
+-- CMakeLists.txt
+-- bar.h
+-- bar.cpp
(For the interested, the entire code of this example project can be checked out from here)
The top-level CMakeLists.txt contains (among others) the statements enable_testing() and add_subdirectory(test). Compiling and running test cases works perfectly with this setup, simply by running
mkdir build && cd build
cmake ..
make
make test
But how would I compile this project into production code, i.e. only the components test, libfoo and libbar, without all the unit tests?
Should I make the statements enable_testing() and add_subdirectory(test) somehow dependent on some build configuration variables? Or what's the best practice for this?
To build the tests only on request, I do it in this way:
Add an option option(BUILD_TEST "Build the unit tests" ON)
Include the test subdirs only in case BUILD_TEST is on
if(BUILD_TEST)
add_subdirectory(test)
endif()
In your case you can modify this to testfoo.
As you asked for production, you can use the following instead to build in debug mode only:
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
add_subdirectory(test)
endif()
What I do is to make a custom macro for unit test creation which does this:
set_target_properties(${NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/test)
Then your tests will end up in a special directory (test) instead of the regular one (usually bin). Then for production you just copy the regular directory without the test directory.

Build and use GTest globally in a project

First, I need to claim that I have been going around Stack Overflow and arrive answers of how to use ExternalProject to build Google Test within a project, for example here.
Now let's say what I have in my project is something like this
+-- CMakeLists.txt (the big CMake File for the entire project)
+-- tests
| +-- CMakeLists.txt (contain of all the small project in the tests)
| +-- Test1
| +-- CMakeLists.txt (test file for Test1 program)
| +-- test_1.cpp
| +-- test_1.h
| +-- Test2
| +-- CMakeLists.txt (test file for Test2 program)
| +-- test_2.cpp
| +-- test_2.h
| +-- Test3
| +-- CMakeLists.txt (test file for Test3 program)
| +-- test_3.cpp
| +-- test_3.h
Now, is there anyway that I can configure and build Google Test using ExternalProject in the big CMakeLists.txt file (at the root folder), and then use those library to build each separate tests in their corresponding folder. At the moment I can only download-built-link an entire new set of GTest libraries in each of the sub folder Test1, Test2, Test3 which is very inefficient. Is there an alternative way to get around this?
It is unclear without seeing your actual CMakeLists.txt files what's happening in your case. That said, used in the normal way, ExternalProject doesn't give you the CMake targets to link to directly, you have to do more manual work to get something you can add to the linked library list of your targets needing to use GTest. So depending on how you've manually defined those things, that could be why you are finding you need to build GTest in each TestX subdirectory.
In the other SO question you linked to, my answer there and the linked article therein mentions how to download and build GTest as part of the CMake stage rather than at build time. This gives you the CMake targets which you can then link against directly without having to define them manually. If you follow that method to download and build GTest in your top level CMakeLists.txt file, then the gtest and gtest main targets will be visible to all subdirectories. Furthermore, you won't have to go figure out the name of the library for each platform, etc. since the CMake target already handles that for you. Thus, in your various Test1, Test2 and Test3 subdirectories, all you'd have to do is to add gtest or gtest_main to the list of libraries each test program linked against.
My approach is to create a directory at the same level of your test projects:
+-- CMakeLists.txt (the big CMake File for the entire project)
+-- tests
| +-- CMakeLists.txt (contain of all the small project in the tests)
| +-- gtest
| +-- CMakeLists.txt (use ExternalProject_Add to import GTest)
| +-- Test1
| +-- CMakeLists.txt (test file for Test1 program)
| +-- test_1.cpp
| +-- test_1.h
| +-- Test2
| ...
In the CMakeLists.txt for gtest I define the gtest target and export the variables for the include dir and library path for the other projects to use.
It works for me and I get gtest built only once so all test projects can link against it. But I'll try to give a shot to Craig Scott's approach to build gtest during Makefile generation instead of at build time.
The CMakeLists.txt file under the gtest folder looks like this:
cmake_minimum_required(VERSION 2.8.11)
include(ExternalProject)
set(GMOCK_VERSION "1.7.0")
set(GMOCK_DIR "${CMAKE_CURRENT_BINARY_DIR}/gmock-${GMOCK_VERSION}")
ExternalProject_Add(project_gmock
SVN_REPOSITORY http://googlemock.googlecode.com/svn/tags/release-${GMOCK_VERSION}
PREFIX ${GMOCK_DIR}
CMAKE_ARGS -DCMAKE_C_COMPILER:PATH=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER:PATH=${CMAKE_CXX_COMPILER}
# Disable update step
UPDATE_COMMAND ""
# Disable install step
INSTALL_COMMAND ""
)
ExternalProject_Get_Property(project_gmock source_dir)
ExternalProject_Get_Property(project_gmock binary_dir)
include_directories(${source_dir}/gtest/include)
add_library(gtest STATIC IMPORTED GLOBAL)
set_target_properties(gtest PROPERTIES IMPORTED_LOCATION ${binary_dir}/gtest/libgtest.a)
set_target_properties(gtest PROPERTIES INCLUDE_DIRECTORIES ${source_dir}/gtest/include)
add_dependencies(gtest project_gmock)
get_property(GTEST_INCLUDE_DIR TARGET gtest PROPERTY INCLUDE_DIRECTORIES)
set(GTEST_INCLUDE_DIR "${GTEST_INCLUDE_DIR}" PARENT_SCOPE)
add_library(gtest_main STATIC IMPORTED GLOBAL)
set_target_properties(gtest_main PROPERTIES IMPORTED_LOCATION ${binary_dir}/gtest/libgtest_main.a)
add_dependencies(gtest_main project_gmock)
include_directories(${source_dir}/include)
add_library(gmock STATIC IMPORTED GLOBAL)
set_target_properties(gmock PROPERTIES IMPORTED_LOCATION ${binary_dir}/libgmock.a)
set_target_properties(gmock PROPERTIES INCLUDE_DIRECTORIES ${source_dir}/include)
add_dependencies(gmock project_gmock)
get_property(GMOCK_INCLUDE_DIR TARGET gmock PROPERTY INCLUDE_DIRECTORIES)
set(GMOCK_INCLUDE_DIR "${GMOCK_INCLUDE_DIR}" PARENT_SCOPE)
add_library(gmock_main STATIC IMPORTED GLOBAL)
set_target_properties(gmock_main PROPERTIES IMPORTED_LOCATION ${binary_dir}/libgmock_main.a)
add_dependencies(gmock_main project_gmock)