how do i build libraries in subdirectories using cmake? - c++

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.

Related

cmake using two shared libraries that are dependant on each other

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)

"No such file or directory" when linking shared library with CMake [duplicate]

This question already has answers here:
How to properly add include directories with CMake
(12 answers)
CMake link to external library
(6 answers)
Closed 1 year ago.
I have am trying to link a precompiled so file to my executable in cmake. I'm not sure if I am misunderstanding how to use a shared library or not but I assumed that once I compile a shared library, any application can link to it and use it's functions. When compiling the executable, I get this error:
logger.h: No such file or directory
#include "logger.h"
^~~~~~~~~~
compilation terminated.
Here is my cmake file for the executable
cmake_minimum_required(VERSION 2.8)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# set PROJECT home directory
set(PROJECT_HOME "/opt/PROJECT")
# set the project name
project(ClServer)
# add the executable
add_executable(ClServer server.cpp)
add_library(logger SHARED IMPORTED libClLogger.so)
message ("Here")
set_target_properties(logger
PROPERTIES IMPORTED_LOCATION "#{PROJECT_HOME}/base"
)
target_link_libraries(ClServer
${Logger}
)
I've also tried using find_library and adding an absolute path to the shared library using target_link_libraries, but the same error occurs.
Here is my cmake file for the logger shared library:
cmake_minimum_required(VERSION 2.8)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# set Clamor home directory
set(PROJECT_HOME "/opt/PROJECT")
# set the project name
project(ClLogger)
# set boost paths
set(Boost_NO_SYSTEM_PATHS TRUE)
if (Boost_NO_SYSTEM_PATHS)
set(BOOST_ROOT "${PROJECT_HOME}/ext/Boost/boost_1_76_0")
set(BOOST_LIBRARYDIR "${PROJECT_HOME}/ext/Boost/boost_1_76_0/stage/lib")
set(BOOST_INCLUDEDIR "${PROJECT_HOME}/ext/Boost/boost_1_76_0")
endif (Boost_NO_SYSTEM_PATHS)
# provides the linker with the appropriate directories and components
find_package(Boost 1.76.0 COMPONENTS log log_setup thread filesystem system)
if(Boost_FOUND)
include_directories(${BOOST_INCLUDEDIR})
link_directories(${BOOST_LIBRARYDIR})
endif()
message (STATUS Boost_LIBRARIES:)
message (STATUS ${Boost_LIBRARIES})
message (STATUS BOOST_INCLUDEDIR:)
message (STATUS ${BOOST_INCLUDEDIR})
# add PROJECT source code libraries
add_library(ClLogger SHARED logger.cpp)
# link the appropriate libraries
target_link_libraries(ClLogger
libpthread.so.0
${Boost_LIBRARIES}
)
# redirect binaries to base folder
set_target_properties(ClLogger
PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_HOME}/base"
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_HOME}/base"
RUNTIME_OUTPUT_DIRECTORY "${PROJECT_HOME}/base"
)
To consume a shared library, you need two things. First, shared library file and second public header file. Header file will get used in compilation stage and shared library file in linking stage. Error you are seeing is a compilation failure which says it failed to find header file "logger.h". Use target_include_directories in cmake of your executable to tell cmake where to look for header logger.h.
Additionally if you want cmake to keep watch on logger.h modification, you can add logger.h as source file of your executable.
After a bit of research and testing in my local machine,
i have updated my answer with the simple example tested on eclipse CDT and cmake in WSL2.(should work on any other environment fine ).
the following example should provide an answer to the question.
cmake_test/
├── CMakeLists.txt
├── build
├── cmake_test.cpp
└── **companyLibrary**
├── CMakeLists.txt
├── build
├── include
│   └── Company.h
└── src
└── Company.cpp
from the above project hierarchy companyLibrary is the one which generates the .so (shared Library), which will be used by cmake_test.cpp source file which is at the root level of the project.
cmake_test/companyLibrary/CMakeLists.txt
cmake_minimum_required (VERSION 2.6)
project (companyLibrary_test)
set(CMAKE_BUILD_TYPE Release)
#adding the header <.h> files into the project
include_directories(include)
file(GLOB SOURCES "src/*.cpp")
add_library(testCompany SHARED ${SOURCES})
install(TARGETS testCompany DESTINATION /usr/lib)
this generates the .so file in this example (libtestCompany.so)
sudo make install
this will put .so file in /usr/lib folder
now this shared library will be used by the root project cmake_test.cpp file
cmake_test/CMakeLists.txt
cmake_minimum_required (VERSION 2.6)
project (cmake_test)
set ( PROJECT_LINK_LIBS libtestCompany.so )
link_directories( "/usr/lib" )
include_directories( "companyLibrary/include" )
add_executable( libtest cmake_test.cpp )
target_link_libraries( libtest ${PROJECT_LINK_LIBS} )
add_executable and target_link_libraries should solve the problem
as show above.
full source code availabe here on GitHub.
hope it helps :)

how to stop cmake to rebuild static libraries if they already present

I have following project structure
CmakeLists.txt
src/main.cpp
A/CMakeLists.txt
A/test.cpp
B/CMakeLists.txt
B/other.cpp
libs/
The build configuration is written in a way that the
sub-directories are compiled as static libraries (stored into libs) and then they are used to produce final binary.
Now suppose I transfer this project to my bud, with only CMakeLists.txt, source-files and static libraries in libs.
When compiling the project, he/she have to recompile again all the source files, despite the libraries are already there.
Is there any way to tell cmake to re-use pre-build static libraries ??
Excerpt from top cmakelist.txt .
add_subdirectory (${PROJECT_SOURCE_DIR}/src/A)
add_subdirectory (${PROJECT_SOURCE_DIR}/src/B)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/libs)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/libs)
add_executable(myBinary ${PROJECT_SOURCE_DIR}/src/main.cpp )
add_dependencies(myBinary A B)
target_link_libraries (myBinary A B)
Subdirectory cmakelist.txt .
project (A)
file(GLOB SOURCES "*.cpp")
add_library (A STATIC ${SOURCES})

Right way of creating a library, installing it and linking to another project using CMake

I have a set of files that I want to make into a library and then use that library in another project. This it how it looks like right now
cmake_minimum_required(VERSION 2.8)
aux_source_directory(. SRC_LIST)
SET(CMAKE_CXX_FLAGS "-std=c++11 -fopenmp -fPIC")
add_library (helperlibs lib1.cpp lib2.cpp lib3.cpp lib4.cpp )
INSTALL(TARGETS helperlibs
DESTINATION "${HOME}/lib"
)
INSTALL(FILES lib1.h lib2.h lib3.h lib4.h helperheader.h
DESTINATION "${HOME}/include/helperlibs"
)
In this code Lib4 depends on Lib1-3 and Lib3 depends on Lib1-2 and Lib2 depends on Lib1. Each of these cpp files also depend on a helperheader.h file that contains some definitions and structs.
In my project I have the following CMake file
cmake_minimum_required(VERSION 2.8)
aux_source_directory(. SRC_LIST)
SET( CMAKE_CXX_FLAGS "-std=c++11 -fopenmp -fPIC")
SET(MYINCS ${HOME}/include/helperlibs)
SET(MYLIBDIR ${HOME}/lib)
SET(MYLIBS ${MYLIBDIR}/libhelperlibs.a )
include_directories(${MYINCS})
add_executable(main main.cpp)
target_link_libraries(main ${MYLIBS})
So what I am wondering if you want to create a static library and link to from a another project using cmake is this the way you should write?
Embed the search paths into the library target as properties and create an export.
This way executables in the same build tree will find the library and its include files without you having to specify paths (they become implicit).
I needed to read the cmake documentation carefully a few times before it dawned on me how it should work.
http://www.cmake.org/cmake/help/v3.0/manual/cmake-packages.7.html#creating-packages
http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html
excerpt from a live example:
add_library(trustportal-util ${CMAKE_CURRENT_LIST_FILE} ${_source_files} ${_disabled_source_files} )
target_link_libraries(trustportal-util ${Boost_LIBRARIES})
if(APPLE)
find_library(SECURITY_FRAMEWORK Security)
target_link_libraries(trustportal-util ${SECURITY_FRAMEWORK})
else()
find_library(LIB_SSL ssl)
find_library(LIB_CRYPTO crypto)
target_link_libraries(trustportal-util ${LIB_SSL} ${LIB_CRYPTO})
endif()
target_compile_definitions(trustportal-util PUBLIC BOOST_MOVE_USE_STANDARD_LIBRARY_MOVE)
target_include_directories(trustportal-util PUBLIC ${Boost_INCLUDE_DIRS})
target_include_directories(trustportal-util PRIVATE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
target_include_directories(trustportal-util SYSTEM PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
install(TARGETS trustportal-util
EXPORT trustportal-utilExport
DESTINATION lib
INCLUDES DESTINATION include
)
INSTALL(EXPORT trustportal-utilExport DESTINATION lib)
One option is to do what you are currently doing where you place the includes and libs in a common location, perhaps /usr/include and /usr/lib on linux, or ${HOME} on both Windows/Linux, up to you.
Another option is available if you use git. You can include the project inside another using submodules. Then use include_directory(${submodule}) and build and link directly for every project. The advantage of this approach is that dependencies are more localised. One problem with this method is if you recursively do this, you may end up with duplicates of some projects and cmake will complain that two libraries have the same name.

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