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

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

Related

"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 :)

Integrating GTest with existing CMake Project: share the same target_sources

I have a large C++ library, and want to do some testing with GTest.
At the moment, the build is handled with CMake, in particular there is one CMakeLists.txt file in the root directory like the following
make_minimum_required(VERSION 3.13.0)
project(mylib)
find_package(PkgConfig REQUIRED)
set(CMAKE_BUILD_WITH_INSTALL_RPATH ON)
set(CMAKE_INSTALL_RPATH "${CMAKE_CURRENT_SOURCE_DIR}/lib/protobuf/src/.libs/")
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
SET(BASEPATH "${CMAKE_SOURCE_DIR}")
INCLUDE_DIRECTORIES("${BASEPATH}")
add_executable(mylib run.cpp)
add_subdirectory(src)
add_subdirectory(proto)
target_include_directories(mylib PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/lib/math
${CMAKE_CURRENT_SOURCE_DIR}/lib/protobuf/src
... some dirs ...
)
target_link_directories(mylib PRIVATE
... some libs ..
)
target_link_libraries(mylib
${CMAKE_CURRENT_SOURCE_DIR}/lib/math
${CMAKE_CURRENT_SOURCE_DIR}/lib/protobuf/src
.....
)
target_compile_options(mylib PUBLIC -D_REENTRANT -fPIC)
Then in the src directory and every sub-directory there is a CMakeLists.txt file, for example this is in src/
target_sources(mylib
PUBLIC
includes.hpp
)
add_subdirectory(algorithms)
add_subdirectory(collectors)
add_subdirectory(hierarchies)
add_subdirectory(mixings)
add_subdirectory(runtime)
add_subdirectory(utils)
My question here is the following: what is the least painful way to integrate GTest in the current project? I was thinking of having a test/ subdirectory, like I've seen here: Adding Googletest To Existing CMake Project
However this example requires that for each executable you manually list all the files it includes. Is there a quicker way to use the sources that are already added to 'mylib'?
You can split the current mylib executable target into two targets
mylib, a library target that is very much like the current mylib target, but without the run.cpp file
mylib_exe an executable target that compiles run.cpp and links to mylib
Now your test files can link to mylib.

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.

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