Using CMake to statically link to a library outside of the project - c++

I would like to use CMake to link my project to my shared library. The library is only shared between a handful of projects and is rather small, so I would really like to build it before it is linked. Building it every time seems a better idea than having to maintain an up-to-date precompiled version, because I ten to change it together with the project. It is separate, because it contains stuff I will almost certainly need in the next project.
How can I configure CMake to do it?
My current CMakeLists.txt for the relevant project looks like this:
find_package( Boost REQUIRED COMPONENTS unit_test_framework)
include_directories(${BaumWelch_SOURCE_DIR}/../../grzesLib/src
${BaumWelch_SOURCE_DIR}/src
${Boost_INCLUDE_DIRS})
if(CMAKE_COMPILER_IS_GNUCXX)
add_definitions(-g -std=c++11 -Wall -Werror -Wextra -pedantic -Wuninitialized)
endif()
# Create the unit tests executable
add_executable(
baumwelchtests stateindextest.cpp baumiterationtest.cpp baumwelchtest.cpp sampleparameters.cpp sdetest.cpp
# Key includes for setting up Boost.Test
testrunner.cpp
# Just for handy reference
exampletests.cpp
)
# Link the libraries
target_link_libraries( baumwelchtests ${Boost_LIBRARIES} baumwelchlib grzeslib)
but obviously the compilation fails with:
/usr/bin/ld: cannot find -lgrzeslib

You mentioned you'd like to build the library rather than use a precompiled version. If the library has a CMakeList, you should add it using add_subdirectory(path/to/the/library/source/directory). It will then become a subproject of your project and you can use names of its targets normally in your CMakeList.
Note that while the command is called add_subdirectory, it can be an arbitrary directory on disk; it doesn't have to be a subdirectory of the master project's source dir. In case it's not a subdirectory, you have to explicitly specify a binary directory for it as well. Example:
add_subdirectory(/path/to/the/library/source/directory subproject/grzeslib)
The second argument, if given as a relative path, is interpreted relative to CMAKE_CURRENT_BINARY_DIR.

Related

CMake: target_include_directories() can't find header files

At the top of my main.cpp file, No such file or directory is thrown at #include <sqlite3.h>.
Building the code manually by g++ -I"C:\Libraries\64_bit\SQLite3\include\" -L"C:\Libraries\64_bit\SQLite3\bin\" -lsqlite3 main.cpp Class1.cpp Class1.h Class2.cpp Class2.h -o main throws no errors.
CMake cannot seem to find the header, even though I've explicitly described where it is located in my file-system. According to the documentation for target_include_directories(), that should be enough:
Specified include directories may be absolute paths or relative paths. Repeated calls for the same append items in the order called.
Why is the target_include_directories() function not finding the headers, even though I've provided the exact absolute path?
I'm developing on a 64-bit Windows 10 machine, and CLion is set-up to compile with the MinGW-w64 g++ compiler.
I've downloaded the 64-bit Windows pre-compiled binary, sqlite3.dll and stored it locally in C:\Libraries\64_bit\SQLite3\bin\.
In order to access SQLite C++ functions I've also downloaded SQLite3's amalgamated source code and stored all source files in C:\Libraries\64_bit\SQLite3\include\.
I built my project in CLion, which is essentially a fancy GUI-wrapper for CMake. In my CMakeLists.txt, I've included SQLite3's headers and linked sqlite3 as follows:
cmake_minimum_required(VERSION 3.7)
project(My_Project)
set(CMAKE_CXX_STANDARD 11)
set(INCLUDE_DIRS C:\\Libraries\\64_bit\\SQLite3\\include\\)
set(LIBRARIES sqlite3.dll)
# My project's source code
set(SOURCE_FILES main.cpp Class1.cpp Class1.h Class2.cpp Class2.h)
add_executable(My_Project ${SOURCE_FILES})
# For compiler warnings
target_compile_options(My_Project PRIVATE -Wall)
# Including SQLite3's headers
target_include_directories(My_Project PRIVATE ${INCLUDE_DIRS})
# Linking against sqlite3.dll
target_link_libraries(My_Project ${LIBRARIES})
You can run into problems if you don't put paths between quotes.
Thus it is a good idea to write:
set(INCLUDE_DIRS "C:\\Libraries\\64_bit\\SQLite3\\include\\")
or, rather:
set(INCLUDE_DIRS "C:/Libraries/64_bit/SQLite3/include/")
Additionally, the CMakeLists.txt as it currently stands won't be able to find -lsqlite3. Thankfully, CMake makes finding libraries easy:
# Optionally, add 'PATHS "C:/Libraries/64_bit/SQLite3/bin/"'
find_library(SQLITE3_LIBRARY NAMES sqlite3)
If the library is discover-able on your system, the above command will return the path to the library and store that path in SQLITE3_LIBRARY. All that remains to do is link the project against the SQLite3 library:
# Link project to the SQLite3 library
target_link_libraries(MSP_Tool ${SQLITE3_LIBRARY})

Cmake configuration for multiple sub-libraries in a "packages" directory

Here is a sample project I am trying to build with a "Packages" directory which includes all the libraries to be used in the main code.
I am trying to keep my root cmake file as clean as possible and avoid relative path such as
include_directory(packages/lib1)
but I am struggling. Is there a way of including sub-directories of a directory for the purposes of header inclusion.
First a few minor remarks:
always name the CMake configuration files CMakeLists.txt (because of)
bookmark the documentation on CMake: https://cmake.org/documentation/
Sometimes it's not that easy to read, but very specific once you adopt your head to the "CMake world" ;-)
make yourself comfortable with the scope of CMake variables
include_directories(DIR1 [DIR2 [...]])
Tells CMake where the compiler should look for header files, i.e. -IDIR1 -IDIR2 ....
add_library(NAME [STATIC|SHARED] SOURCES)
This command creates the required compiler commands to create a static or shared library out of a given list of source files. No need to add in the header files. The make target will be called NAME and the library target is known to CMake as NAME.
add_subdirectory(DIR)
Tells CMake to look into DIR and parse the included CMakeLists.txt with all its content.
target_link_libraries(TARGET LIB1 [LIB2 [...]])
Tells CMake to instruct the linker to link LIB1, LIB2, etc. to the TARGET, i.e. -LLIB1 -LLIB2 .... TARGET is a CMake/make target previously defined/created with a call to add_{library,executable,custom_target}.
CMakeLists.txt:
include_directories(libraries)
# a header file in `libraries/lib1/foo.hpp` can be included
# in the whole CMake project by `#include "lib1/foo.hpp"`.
add_subdirectory(libraries)
add_subdirectory(tests)
libraries/CMakeLists.txt:
add_subdirectory(lib1)
add_subdirectory(lib2)
libraries/lib1/CMakeLists.txt:
add_library(lib1 STATIC ${LIB1_SOURCES})
libraries/lib2/CMakeLists.txt:
add_library(lib2 STATIC ${LIB2_SOURCES})
tests/CMakeLists.txt:
add_executable(tests ${TEST_SOURCES})
target_link_libraries(tests lib1 lib2)

Cannot find library with simple C++ example

I am building a C++ library called alpha in Ubuntu with cmake, which contains one source file:
cmake_minimum_required(VERSION 2.8)
project(Alpha)
add_library (alpha alpha.cpp)
This creates a file called libalpha.a, which I now want to link to. So, I copy it into the source directory of another C++ projected called beta, which also contains one source file:
cmake_minimum_required(VERSION 2.8)
project(Beta)
add_executable(beta beta.cpp)
target_link_libraries(beta alpha)
However, I get the following error:
/usr/bin/ld: cannot find -lalpha
The same thing happens if I use the line:
target_link_libraries(beta libalpha.a)
Why can beta not find the alpha library?
If you wish to build the library and the program completely separately, you have to use imported targets. When you try to link your executable against a "completely unknown" library, CMake build system automatically passes the task of locating the library to the linker, simply adding -lalpha option. When the linker encounters the option it attempts to locate libalpha.so in one of the standard library locations (i.e. /usr/lib/, /usr/local/lib etc) and expectedly fails. You can use an absolute path to the libalpha.a: target_link_libraries(beta /path/to/libalpha.a).
However if you can build things together, this greatly simplifies the task. Consider
<project>/CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
Project(Test)
add_subdirectory(alpha)
add_subdirectory(beta)
<project>/alpha/CMakeLists.txt
cmake_minimum_required(VERSION 2.8.11)
project(alpha)
set(SOURCES alpha.c)
add_library(alpha ${SOURCES})
target_include_directories(
alpha INTERFACE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>"
)
target_include_directories() with the complex expression within is required to automatically add libalpha include directories to all components which later are linked against libalpha.
<project>/beta/CMakeLists.txt
project(beta)
set(SOURCES beta.c)
add_executable(beta ${SOURCES})
target_link_libraries(beta alpha)
Add this line with the path to alpha-library.
link_directories( <library path> )

Why isn't cmake locating gtest and gmock libs?

Here's a link to my project, just in case.
So, here's my CMakeLists.txt file:
cmake_minimum_required (VERSION 2.6)
enable_testing()
project (IeiuniumTela)
set (IeiuniumTela_VERSION_MAJOR 1)
set (IeiuniumTela_VERSION_MINOR 0)
set (IeiuniumTela_VERSION_PATCH 0)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build/bin)
# TODO: Make conditional for OS X compilation
set(CMAKE_CXX_COMPILER g++-4.7)
set(CMAKE_CC_COMPILER gcc-4.7)
# TODO: Require gcc >= 4.7
set(SOURCES "${SOURCES}" "${CMAKE_BINARY_DIR}/src/http/request.cpp")
set(SOURCES "${SOURCES}" "${CMAKE_BINARY_DIR}/src/http/response.cpp")
set(SOURCES "${SOURCES}" "${CMAKE_BINARY_DIR}/src/http/server.cpp")
set(SOURCES "${SOURCES}" "${CMAKE_BINARY_DIR}/src/log.cpp")
set(SOURCES "${SOURCES}" "${CMAKE_BINARY_DIR}/src/main.cpp")
set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "-Wall ${CMAKE_CXX_FLAGS}")
add_executable(ieiunium_tela.srv ${SOURCES})
target_link_libraries(ieiunium_tela.srv yaml-cpp)
target_link_libraries(ieiunium_tela.srv boost_system-mt)
set(GTEST_DIR "${CMAKE_BINARY_DIR}/../gtest-1.6.0")
include_directories(SYSTEM "${GTEST_DIR}/include")
find_library(GTEST_LIBRARY
NAMES gtest
libgtest
libgtest.a
PATHS "${GTEST_DIR}")
find_library(GTEST_LIBRARY_MAIN
NAMES gtest_main
libgtest_main
libgtest.a
PATHS "${GTEST_DIR}")
set(GMOCK_DIR "${CMAKE_BINARY_DIR}/../gmock-1.6.0")
include_directories(SYSTEM "${GMOCK_DIR}/include")
include_directories(SYSTEM "${GMOCK_DIR}/gtest/include")
find_library(GMOCK_LIBRARY
NAMES gmock
libgmock
libgmock.a
PATHS "${GMOCK_DIR}")
find_library(GMOCK_LIBRARY_MAIN
NAMES gmock_main
libgmock_main
libgmock_main.a
PATHS "${GMOCK_DIR}")
set(TEST_SOURCES "${TEST_SOURCES}" "${CMAKE_BINARY_DIR}/test/unit/http/test_request.cpp")
set(TEST_SOURCES "${TEST_SOURCES}" "${CMAKE_BINARY_DIR}/test/unit/http/test_response.cpp")
set(TEST_SOURCES "${TEST_SOURCES}" "${CMAKE_BINARY_DIR}/test/unit/http/test_server.cpp")
set(TEST_SOURCES "${TEST_SOURCES}" "${CMAKE_BINARY_DIR}/test/unit/test_log.cpp")
set(TEST_SOURCES "${TEST_SOURCES}" "${CMAKE_BINARY_DIR}/test/unit/test_main.cpp")
add_executable(ieiunium_tela.srv_TEST ${TEST_SOURCES})
target_link_libraries(ieiunium_tela.srv_TEST ${GTEST_LIBRARY} ${GTEST_LIBRARY_MAIN})
target_link_libraries(ieiunium_tela.srv_TEST ${GMOCK_LIBRARY} ${GMOCK_LIBRARY_MAIN})
And, here's my question: Why isn't cmake finding my gtest/gmock libs?
I've gone into their respective directories and built them using ./configure && make -j4 and a brief find for the shared libraries shows them there.
Another option would be to build gtest and gmock as part of your main CMake build rather than building them separately and using find_package() or find_library(). This comes with some advantages, including:
They are built with the same compiler and settings as your main build, so there won't be issues with mismatched symbols, etc.
No manual steps required before the build and no need to tell CMake where to find things in your main CMakeLists.txt.
I recently wrote an article about how to download and build gtest as part of your build. Unlike the more commonly suggested approaches, my article shows how to download gtest during configure time (i.e. when CMake is run), which then allows you to bring it into your project using add_subdirectory(). This makes the gtest and gtest_main CMake targets directly available to your project, so you can just link against them like any other library. The approach is general and may work for mock too. You can find that article here:
https://crascit.com/2015/07/25/cmake-gtest/
Update: This approach is now also part of the googletest documentation.
The gtest/gmock libraries aren't built to the actual root of these projects. I believe on Linux they're built to "lib" inside the root.
To tell CMake to search in "lib" but without modifying your GTEST_DIR or GMOCK_DIR variables, you can use the PATH_SUFFIXES argument to the find_library command:
find_library(GTEST_LIBRARY
NAMES gtest
libgtest
libgtest.a
PATHS "${GTEST_DIR}"
PATH_SUFFIXES lib)
You can add a list of suffixes to give values appropriate for Windows builds too if required.
There is a standard CMake module provided to find gtest (FindGTest). You could look at the code in there for ideas, or actually use it instead of your own code. Unfortunately, there isn't a FindGMock module.
I have a couple of other minor points.
It might be worth considering allowing the GTEST_DIR and GMOCK_DIR variables to be set by the user via the -D flag to allow these to exist anywhere relative to your project's root. In that case, you'd only set them inside the CMakeLists.txt if they weren't already set.
Another minor point is that GMock comes with GTest included. You could just allow users to build GMock, and then find and use the version inside the GMock tree.

how to include NTL using CMake

I use this line to compile a simple program:
g++ main.cc -lntl -lm -lgmp
How do you include this into CMake?
find_package(NTL REQUIRED)
find_package(GMP REQUIRED)
Doesn't work. And gives the following error:
CMake Error at CMakeLists.txt:30 (find_package):
Could not find module FindNTL.cmake or a configuration file for package
NTL.
...
.
and
SET(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -std=c++0x -lntl -lm -lgmp)
Doesn't work either (but I think it's just wrong in general).
Thank you!
If ntl, m, and gmp libraries are usually installed to somewhere in the default path (e.g. /usr/ or /usr/local/), you could simply do something like:
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(Test)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
add_executable(test main.cc)
target_link_libraries(test ntl m gmp)
This is probably closest to your original g++ command, but it isn't very robust however; if any of the libraries aren't found, you won't know about it until you try linking. If you want to fail at configure time (i.e. while running CMake), you could add find_library calls for each of the required libs, e.g.
find_library(NTL_LIB ntl)
if(NOT NTL_LIB)
message(FATAL_ERROR "ntl library not found. Rerun cmake with -DCMAKE_PREFIX_PATH=\"<path to lib1>;<path to lib2>\"")
endif()
You'd then have to change your target_link_libraries command to
target_link_libraries(test ${NTL_LIB} ${M_LIB} ${GMP_LIB})
You'd probably also then have to do a find_file for one of each lib's header files to find out the appropriate path to add via the include_directories command (which translates to -I for g++).
Note, it's important to put quotes around the extra CXX_FLAGS arguments, or CMake treats them like separate values in a list and inserts a semi-colon between the flags.
For further information about find_library, find_file, etc. run:
cmake --help-command find_library
cmake --help-command find_file
Regarding your error:
It doesn't look like there's a FindNTL.cmake module included with CMake. That means you'll have to either:
Write your own FindNTL.cmake,
Find another that somebody else has written,
Hack together a solution that:
Checks if NTL is installed
Provides link targets, relevant flags, etc.
From a (rather quick) Google search, it appears somebody has an NTL module for CMake. Since NTL use GMP, you will probably need the associated GMP module for CMake. It doesn't look like a fully-featured CMake module, but it also appears to be the best thing out there (again, it was a quick Google search, and I don't use NTL).
To use, you'll want to add some things to your CMakeLists.txt:
# Let CMake know where you've put the FindNTL.cmake module.
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/build/CMake/Modules")
# Call the FindNTL module:
find_package(NTL REQUIRED)
SET(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -std=c++0x -lntl -lm -lgmp)
Yes, this is wrong. You don't want to be setting your CXX_FLAGS with linking directives. I would use:
SET ( CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -std=cxx0x )
to set the Cxx standard you want to use. To actually link to libraries, you'll want to:
Ensure that you've found the libraries (with the relevant find_package ( FOO ) lines)
Link those against your target, like this:
# Build the Foo executable. (Or library, or whatever)
add_executable (FooEXE ${Foo_SOURCES} )
target_link_libraries (FooEXE
${bar_LIBRARIES}
${baz_LIBRARY}
)
Please note! ${bar_LIBRARIES} and ${baz_LIBRARY} is not a typo; there's no standard way of setting the relevant libraries in the FindFOO.cmake modules, which is, in my opinion, an annoyance. If one doesn't work, try the other, or, worst case, have a look in the relevant FindFOO.cmake file (there's a bunch installed with CMake by default) to see what each one uses. With the link i provided, you can use ${NTL_LIB} and ${GMP_LIB}.