cmake using two shared libraries that are dependant on each other - c++

I'm trying to build a program, that is dependant on two other projects (ugh and thermough). thermough is dependant on ugh and both have multiple libraries.
The code species.cpp is the following:
#include "Test.h"
#include "tabstream.h"
#include <fstream>
int main()
{
ugh::Test tp("water");
std::ofstream file;
tabstream tfile(file,16);
file.open("water");
tfile << "T"
<< std::endl;
return 0;
}
This is my CMakeLists.txt:
####################################
# General setup
####################################
cmake_minimum_required (VERSION 3.5.2)
project (getSpeciesTest VERSION 1.0)
set(CMAKE_VERBOSE_MAKEFILE OFF)
include(CMakePrintHelpers)
####################################
# Executable
####################################
add_executable(specieTestEx species.cpp)
#configure_file(TutorialConfig.h.in TutorialConfig.h)
####################################
# Libraries, etc
####################################
set(PATH_TO_SRC ${PROJECT_SOURCE_DIR}/../src)
set(PATH_TO_THERMOUGH ${PROJECT_SOURCE_DIR}/../../build)
set(PATH_TO_UGH ${PROJECT_SOURCE_DIR}/../../../ugh/build)
set(PATH_TO_UGH_SRC ${PROJECT_SOURCE_DIR}/../../../ugh/git/src)
include_directories (${PATH_TO_SRC})
include_directories (${PATH_TO_SRC}/ughMixture)
include_directories (${PATH_TO_SRC}/mathUtils)
include_directories (${PATH_TO_UGH})
include_directories (${PATH_TO_UGH_SRC}/ughBase)
include_directories (${PATH_TO_UGH_SRC}/ughMixture)
include_directories (${PATH_TO_UGH_SRC}/ughMath)
include_directories (${PATH_TO_UGH_SRC}/ughMath/math1)
include_directories (${PATH_TO_UGH_SRC}/ughMath/math2)
include_directories (${PATH_TO_UGH_SRC}/ughMath/math3)
include_directories (${PATH_TO_UGH_SRC}/ughMath/math4)
list(APPEND LIBS_THERMOUGH [...])
list(APPEND LIBS_UGH [...])
##this is where the already built libraries are
link_directories(${PATH_TO_THERMOUGH})
link_directories(${PATH_TO_UGH})
target_link_libraries(specieTestEx ${LIBS_THERMOUGH})
target_link_libraries(specieTestEx ${LIBS_UGH})
I did not write both projects, I'm just trying to use so functionalities from thermough and therefore need to link both libraries. The libraries are as shared libraries in the build folders (.so files). I checked in the CMakeList.txt of thermough and the libraries of both projects are linked there.
My questions now:
As far as I understand it, in the libraries only the .cpp files and not the headers are compiled. Therefore I need to include all the directories to the header files (and if one called function is dependant on another file, i need to include the path to that directory and so on). This leads me to having so many include_directories commands. Is there an easier way?
Secondly I get the following error when compiling:
[SRCdirectory]/../../../ugh/git/src/ughMath/math4/mathImplementation.h:8:32: fatal error: ughMath/MathLog.h: No such file or directory
The path to ughMath is linked in my CMakeList.txt. Why does this happen then and what can I correct?
Thank you for your answer in advance.
Last but not least this is the structure of the code I'm working with:
code
ugh
git
build (contains all ugh_[..].so libraries)
thermough
git
- src
- myTestCase (contains species.cpp and the CMakeList.txt I'm talking about)
build (contains all thermough_[..].so libraries)

Related

Cmake C++ Project With Eigen Headers in src [duplicate]

I am having difficulty using a header-only library (Eigen) in my CMake project. When i take off all the portion related to Eigen library it compiles, but not sure how to build with (Eigen). Note that Eigen has a CmakeLists.txt in Eigen folder, and it has /src folder having (*.h and *.cpp) related to Matrix operation etc...
The structure of my program is as follow
Myproject (folder) is composed of :
CmakeLists.txt
/Build
/Source
The Source folder has bunch of my files (*.h and *.cpp) and the /Eigen (folder).
what i did is :
FIND_PACKAGE(PkgConfig REQUIRED)
PKG_CHECK_MODULES(GTK3 REQUIRED gtk+-3.0)
LIST(APPEND CMAKE_CXX_FLAGS
"-std=c++0x
-pthread
${CMAKE_CXX_FLAGS}
-g
-Wall -Wextra ")
ADD_LIBRARY(Eigen ${CMAKE_SOURCE_DIR}/Eigen)
TARGET_INCLUDE_DIRECTORIES(Eigen INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
$<INSTALL_INTERFACE:include/Eigen>
)
INCLUDE_DIRECTORIES(${GTK3_INCLUDE_DIRS})
ADD_DEFINITIONS(${GTK3_CFLAGS_OTHERS})
INCLUDE_DIRECTORIES(include)
ADD_LIBRARY(RTT
Def.cpp
Def.h
krnel.cpp
krnel.h
Mesh.cpp
Mesh.h
Mcom.cpp
Mcom.h
timer.h
Identifier.h)
ADD_EXECUTABLE(Rdrtst main.cpp)
TARGET_LINK_LIBRARIES(Rdrtst RTT ${GTK3_LIBRARIES} Eigen)
When i cd to /Build and type (Cmake ../Source )
I get the following :
[/../Build]$ cmake ../Source
-- Configuring done
CMake Error: Cannot determine link language for target "Eigen".
CMake Error: CMake can not determine linker language for target:Eigen
-- Generating done
-- Build files have been written to: /../../MyProject/Build
The eigen folder has the CMakeLists.txt with the following content :
include(RegexUtils)
test_escape_string_as_regex()
file(GLOB Eigen_directory_files "*")
escape_string_as_regex(ESCAPED_CMAKE_CURRENT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
foreach(f ${Eigen_directory_files})
if(NOT f MATCHES "\\.txt" AND NOT f MATCHES "${ESCAPED_CMAKE_CURRENT_SOURCE_DIR}/[.].+" AND NOT f MATCHES "${ESCAPED_CMAKE_CURRENT_SOURCE_DIR}/src")
list(APPEND Eigen_directory_files_to_install ${f})
endif()
endforeach(f ${Eigen_directory_files})
install(FILES
${Eigen_directory_files_to_install}
DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen COMPONENT Devel
)
add_subdirectory(src)
You are trying to include Eigen as a compiled library. However, as you have stated, Eigen is really a header only library and does not need to be compiled, just included. There should be no .cpp files at all.
Remove the line
ADD_LIBRARY(Eigen ${CMAKE_SOURCE_DIR}/Eigen)
as that is meant for static or shared libraries. Now that you're not building Eigen, you can remove the line
TARGET_INCLUDE_DIRECTORIES(Eigen ...
The Eigen CMakeLists file really just copies the Eigen header files to an include directory and doesn't compile anything. See this link for an example of how to use Eigen with CMake.
You just need the correct path in INCLUDE_DIRECTORIES (also make sure to include the correct folder or subfolder, depending if in your c++ file you are using #include Eigen/something.h or #include something.h )
So, remove the lines ADD_LIBRARY(Eigen ... and TARGET_LINK_LIBRARIES Eigen.
For troubleshooting, you can also include the absolute path of the Eigen folder , and then when you get it working, transform it in a relative path
This is a late answer, but it might help someone else. These are the precise steps I took in order to include the Eigen lib into my project with CMake files.
First, assuming your project already include the Eigen sub-directory, e.g., at src/third_party/eigen, copy-paste FindEigen3.cmake file into src/cmake.
Second, you might want to edit the FindEigen3.cmake to include your own location hints that you will provide from you CMake file. For example:
find_path( EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library
HINTS "${EIGEN3_ROOT}" "$ENV{EIGEN3_ROOT_DIR}" "${EIGEN3_INCLUDE_DIR_HINTS}"
# ... leave the rest as it is
)
Third, "include" the Eigen from your CMakeLists.txt by specifying the hint EIGEN3_ROOT and the location of the FindEigen3.cmake file:
message(STATUS "Trying to include Eigen library")
set(EIGEN3_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/third_party/eigen)
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
find_package(Eigen3 3.2.0 REQUIRED)
include_directories(${EIGEN3_INCLUDE_DIR})
message(STATUS "EIGEN: " ${EIGEN3_VERSION} " (internal)")
Forth, start using Eigen from within your project:
#include <Eigen/Dense>
using Eigen::MatrixXd;
// ...
MatrixXd m(2,2);
m(0,0) = 3;
m(1,0) = 2.5;
m(0,1) = -1;
m(1,1) = m(1,0) + m(0,1);
std::cout << m << std::endl;

CMake relative linking, executable fails to find shared libraries

I am trying to learn CMake and for that purpose I am working with an example project of the structure shown below. I am trying to configure all the CMakeLists.txt files such that after make install I can copy the resulting build directory and copy-paste it around freely such that other people are able run the executable.
Problem: after running make install (maxOS 10.14.6 (Darwin 18.7.0)) everything works if I run the executable inside build BUT if I move the build directory from its original location - for example to Desktop - the executable is unable to find the shared libraries. It seems that the reason for this is that the paths to the shared libraries are defined as absolute paths instead of relative paths with respect to the build directory.
Question: How can I build the project such that the executable finds the shared libs?
Project structure:
myapp
|
CMakeLists.txt (top-level)
- build
- app
| CMakeLists.txt (app)
| - inc
| - app
| app.h
| - src
| app.cpp
| main.cpp
|
- external
|
- mylib
CMakeLists.txt (mylib)
- inc
- mylib
mylib.h
- src
mylib.cpp
CMakeLists:
CMakeLists.txt (top-level)
cmake_minimum_required(VERSION 3.0)
project(myapp)
add_subdirectory(external/mylib)
add_subdirectory(app)
CMakeLists.txt (app)
# myapp program
cmake_minimum_required(VERSION 3.0)
project(myapp_prog)
set(SOURCES ./src/)
set(HEADERS ./inc/app/)
set(SOURCE_FILES
${SOURCES}/app.cpp)
set(HEADER_FILES
${HEADERS}/app.h)
# All sources that need to be tested in unit test go into a static library
add_library(myapp_lib SHARED ${HEADER_FILES} ${SOURCE_FILES})
target_include_directories(myapp_lib PUBLIC ${HEADERS})
# The main program
add_executable(prog ./src/main.cpp)
target_include_directories(prog PUBLIC ./inc/)
# Link the libraries
target_link_libraries(prog PRIVATE myapp_lib mylib)
install(TARGETS myapp_lib DESTINATION ${CMAKE_BINARY_DIR}/lib)
CMakeLists.txt (mylib)
# mylib
cmake_minimum_required(VERSION 3.0)
project(mylib)
set(SOURCES src/)
set(HEADERS inc/mylib/)
set(SOURCE_FILES
${SOURCES}/mylib.cpp)
set(HEADER_FILES
${HEADERS}/mylib.h)
add_library(mylib SHARED ${HEADER_FILES} ${SOURCE_FILES})
target_include_directories(mylib PUBLIC inc/)
install(TARGETS mylib DESTINATION ${CMAKE_BINARY_DIR}/lib)
C++ code:
mylib.h
void mylib_print_hello();
mylib.cpp
#include "library.h"
#include <iostream>
void mylib_print_hello() {
std::cout << "Hello from mylib!" << std::endl;
}
app.h
void myapp_hello();
app.cpp
#include <iostream>
#include "app.h"
void myapp_hello()
{
std::cout << "Hello from myapp!" << std::endl;
}
main.cpp
#include <iostream>
#include "app/app.h"
#include "mylib/mylib.h"
int main()
{
myapp_hello();
mylib_print_hello();
}
I think the issue is that you might be confusing the build step with the install step. By using ${CMAKE_BINARY_DIR}, you are passing an absolute path to your binary directory (build), which may interfere with the moving of the build afterwards. If you would like to ouput your libraries to a folder after the build, you may set the target of the library with:
set_target_property(<library-name> PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
This will affect only the build stage of your project. As far as installs go, you are better off using only relative paths in the install directives. These paths will be relative to your ${CMAKE_INSTALL_PREFIX} variable. For example, you would use:
install(TARGETS mylib DESTINATION lib)
To install the library under the ${CMAKE_INSTALL_PREFIX}/lib folder. Best practice states that you should NEVER manipulate this variable directly in your CMakeLists.txt files, as it could break a build somewhere down the line. Starting with CMake 3.15, it is possible to use cmake --install to install a project. This command allows setting an installation prefix, such as:
cmake --install . --prefix desired/install/path
With this, all your link path should stay valid.
Please add a macos tag to this question.
I think that you are looking for a relative RPATH. CMake builds the executable with an absolute RPATH, so if you move or rename the build directory the program stop working. In your example, you only need to modify the main program CMakeLists.txt, to change the value of the RPATHs that CMake inserts in your executable.
# The main program
add_executable(prog ./src/main.cpp)
target_include_directories(prog PUBLIC ./inc/)
set_target_properties(prog PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE INSTALL_RPATH "#executable_path/;#executable_path/../external/mylib")
You can verify the values of the LC_RPATHs with this command from your build directory:
$ otool -l app/prog
For dependencies between libraries, it may also be useful "#loader_path" instead of #executable_path. And for other Unix operating systems, use "$ORIGIN". More information here.

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)

how do i build libraries in subdirectories using cmake?

My code is organized like this:
cpp
main.cpp (calls code from dataStructures/ and common/)
CMakeLists.txt (topmost CMakeLists file)
build
common
CMakeLists.txt (should be responsible for building common shared library)
include
utils.h
src
utils.cpp
build
dataStructures
CMakeLists.txt (build dataStructures shared library - dependent on common library)
include
dsLinkedList.h
src
dsLinkedList.cpp
build
build\ directories contain the built target. The actual code can be seen here: https://github.com/brainydexter/PublicCode/tree/master/cpp
As of now, CMakeLists.txt in each of the subdirectories build their own shared libraries. Topmost CMakeLists file then references the libraries and paths like this
Topmost CMakeLists.txt
cmake_minimum_required(VERSION 3.2.2)
project(cpp)
#For the shared library:
set ( PROJECT_LINK_LIBS libcppDS.dylib libcppCommon.dylib)
link_directories( dataStructures/build )
link_directories( common/build )
#Bring the headers, into the project
include_directories(common/include)
include_directories(dataStructures/include)
#Can manually add the sources using the set command as follows:
set(MAINEXEC main.cpp)
add_executable(testDS ${MAINEXEC})
target_link_libraries(testDS ${PROJECT_LINK_LIBS} )
How can I change the topmost CMakeLists.txt to go into subdirectories (common and dataStructures) and build their targets if they haven't been built, without me having to manually build the individual libraries ?
CMakeLists for common :
cmake_minimum_required(VERSION 3.2.2)
project(cpp_common)
set(CMAKE_BUILD_TYPE Release)
#Bring the headers, such as Student.h into the project
include_directories(include)
#However, the file(GLOB...) allows for wildcard additions:
file(GLOB SOURCES "src/*.cpp")
#Generate the shared library from the sources
add_library(cppCommon SHARED ${SOURCES})
dataStructures :
cmake_minimum_required(VERSION 3.2.2)
project(cpp_dataStructures)
set(CMAKE_BUILD_TYPE Release)
#For the shared library:
set ( PROJECT_LINK_LIBS libcppCommon.dylib )
link_directories( ../common/build )
#Bring the headers, such as Student.h into the project
include_directories(include)
include_directories(../common/include/)
#However, the file(GLOB...) allows for wildcard additions:
file(GLOB SOURCES "src/*.cpp")
#Generate the shared library from the sources
add_library(cppDS SHARED ${SOURCES})
Update:
This pull request helped me understand the correct way of doing this:
https://github.com/brainydexter/PublicCode/pull/1
and commitId: 4b4f1d3d24b5d82f78da3cbffe423754d8c39ec0 on my git
You are only missing a simple thing: add_subdirectory.
From the documentation:
add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
Add a subdirectory to the build. The source_dir specifies the directory in which the source CMakeLists.txt and code files are located. If it is a relative path it will be evaluated with respect to the current directory (the typical usage), but it may also be an absolute path. The binary_dir specifies the directory in which to place the output files. If it is a relative path it will be evaluated with respect to the current output directory, but it may also be an absolute path.
http://www.cmake.org/cmake/help/v3.0/command/add_subdirectory.html
It does exactly what you need.

Add external libraries to CMakeList.txt c++

I have my external library as shown in this picture that I create the symbolic links after:
and the headers related to the library in other file:
I'm working with ROS ubuntu and I need to add these libraries to my package to CmakeList.txt:
cmake_minimum_required(VERSION 2.4.6)
include($ENV{ROS_ROOT}/core/rosbuild/rosbuild.cmake)
rosbuild_init()
#set the default path for built executables to the "bin" directory
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
#set the default path for built libraries to the "lib" directory
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
#common commands for building c++ executables and libraries
#rosbuild_add_library(${PROJECT_NAME} src/example.cpp)
#target_link_libraries(${PROJECT_NAME} another_library)
#rosbuild_add_boost_directories()
#rosbuild_link_boost(${PROJECT_NAME} thread)
#rosbuild_add_executable(example examples/example.cpp)
#target_link_libraries(example ${PROJECT_NAME})
rosbuild_add_executable(kinectueye src/kinect_ueye.cpp)
So my question is how can I add these folders (I think the first one that I need to add I'm not sure) to my CmakeList.txt file so as I can use the classes and the methods in my program.
I would start with upgrade of CMAKE version.
You can use INCLUDE_DIRECTORIES for header location and LINK_DIRECTORIES + TARGET_LINK_LIBRARIES for libraries
INCLUDE_DIRECTORIES(your/header/dir)
LINK_DIRECTORIES(your/library/dir)
rosbuild_add_executable(kinectueye src/kinect_ueye.cpp)
TARGET_LINK_LIBRARIES(kinectueye lib1 lib2 lib2 ...)
note that lib1 is expanded to liblib1.so (on Linux), so use ln to create appropriate links in case you do not have them