Install add_subdirectory(A) header files before building add_subdirectory(B) - cmake

I am new to cmake and I am trying to build my code on UNIX and Windows platforms. I have add_subdirectory(A) and add_subdirectory(B). If I build only add_subdirectory(A), it installs headers files to some xyz location and next when I build add_subdirectory(B), it uses headers files from previously installed xyz location. But when I try to build both add_subdirectory(A) and add_subdirectory(B) together, it fails with missing header files from xyz location, as they are not installed. So my question is, is there a way that I can tell cmake to build and install add_subdirectory(A) and then start building add_subdirectory(B).
I tried to look online but no luck.
My master CMakeLists.txt:
add_subdirectory(TradeFlowCommonFrameworkLib/cpp/src)
add_subdirectory(TradeFlowCommonDataLib/cpp/src)
install(EXPORT Findfotmc DESTINATION ${INSTALL_FOTMC}/cmake)
----------------------------------------------------------------

Adding subdirectories does not specify dependancies between them. You have to explicitly link your second executable/library to your first library.
In the sub CMakeLists of your B project (TradeFlowCommonDataLib/cpp/src) you have to add something like this :
target_link_libraries(B A)

Related

CMake: How to build multiple projects exported for find_package() via add_subdirectory()

I have a Library Project that is exported so consumers can use it like so:
find_package(myLibrary)
target_link_libraries(theirLibrary PUBLIC myNamespace::myLibrary)
MyLibrary is the main product but it lives alongside two other projects in our repository, and the layout looks like this:
MyRepository/
MyLibrary/
CMakeLists.txt
include/ //public headers
MyLibrary/ //sources and private headers
MyDependentLibrary/ //another library project
CMakeLists.txt
etc..
MyExample //executable project
CMakeLists.txt
etc..
The dependencies for each project are like so:
MyLibrary: None
MyDependentLibrary: MyLibrary
MyExample: MyLibrary, MyDependentLibrary
MyLibrary and MyDependentLibrary are both set up with install and build directory exports to be compatible with the find_package() command. So to build everthing you:
configure/build MyLibrary
configure MyDependantLibrary setting MyLibrary_DIR when prompted, then build it
configure MyExample setting MyLibrary_DIR and MyDependentLibrary_DIR when prompted, then build it
This workflow is great, most of the time we only want to package MyLibrary without the other projects when we send to customers, but occasionally we want to give them the source for all 3 projects so they have more examples to look at.
For that reason I would love to add a top level CMakeLists.txt file that would I imagine look something like this:
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(MyCombinedProject VERSION 1.0.0 LANGUAGES CXX)
add_subdirectory(MyLibrary)
add_subdirectory(MyDependentLibrary)
add_subdirectory(MyExample)
However this doesn't work. When configuring the "combined" project, MyDependentLibrary is unable to find MyLibrary_DIR, which makes sense, as MyLibrary hasn't been built yet.
Is there a way to add an export to each of the libraries so they can be found when added in this manner in addition to the find_package()? I really don't want to move any CMake code required to build MyLibrary into the top level CMakeLists.txt, as 90% of the time it will be delivered on its own.
You may ship the sources of your library (MyLibrary) with a pseudo config file, which just provides myNamespace::myLibrary target as alias for myLibrary.
MyLibrary/CMakeLists.txt:
# Assuming you create a library
add_library(mylibrary ...)
# Install and export it
install(TARGETS mylibrary EXPORT mylibraryTargets ...)
# and install the file which describes this installation
install(EXPORT mylibraryTargets NAMESPACE myNamespace ...)
# Then you install config file for your library:
install(FILES myLibrary.cmake ...)
# Then just set `MyLibrary_DIR` variable to point into in-source version of config file.
set(MyLibrary_DIR CACHE INTERNAL "A directory with the in-source config file"
${CMAKE_CURRENT_SOURCE_DIR}/cmake
)
And write that in-source config file as follows:
MyLibrary/cmake/MyLibraryConfig.cmake:
add_library(myNamespace::mylibrary ALIAS mylibrary)
That way, find_package(MyLibrary) will work if it is issued after configuring sources of your library (add_subdirectory(MyLibrary)).

How do I specify the files I want CPack to pack into an RPM?

I'm making two rpms with CPack using its component feature. I want one to have .so files and the other to have all header files. I couldn't find any similar questions regarding packaging files in the component feature.
(DEVEL" is the component for my devel rpm)
Right now I have set(CPACK_RPM_DEVEL_INSTALL_FILES path/../file1
...
path/../file2)
just with all my files separated by returns but that does not work at all. What is the correct statement to provide a list of files I need in the rpm?
Currently it produces 3 rpms (I assume the third will just be a complete one with all files which I'm fine generating and not using). Two of the rpms have every file in the repo in them and the third just has two CMake files in it.
cpack_add_component(DEVEL)
//Skipping version, description, name, setting source_dir...
set(CPACK_RPM_COMPONENT_INSTALL ON)
set(CPACK_COMPONENTS_IGNORE_GROUPS 1)
set(CPACK_COMPONENTS_GROUPING ONE_PER_GROUP)
set(CPACK_COMPONENT_DEVEL_DISPLAY_NAME "devel")
set(CPACK_RPM_DEVEL_INSTALL_FILES "/usr/include/opentracing/noop.h
...
/usr/include/opentracing/version.h")
set(CPACK_COMPONENT_DIST_REQUIRED TRUE)
set(CPACK_COMPONENT_DEVEL_REQUIRED TRUE)
set(CPACK_COMPONENTS_ALL DIST DEVEL)
I am calling this from linux command line with cpack -G rpm
In your CMakelists.txt, add something like:
install(TARGETS outputfiles... RUNTIME DESTINATION bin LIBRARY DESTINATION lib)
Then you can use
make package
in your build directory.

forcing cmake install through add_dependencies?

I'm sorry if this is duplicate. I see a lot of post that are similar, but I am either not "getting" it or it is not exactly the same issue.
I need to build two shared libraries. They are in the same directory structure, and they both get but in to bin. One is dependent on the other.
I've been reading up on add_dependencies, but that seems to deal with project builds outside of cmake. These are both inside
Directory structure
src
CMakeLists.txt
bin
xml
CMakeLists.txt
XML.c
utils.c
XMLSPCL.c
src/CMakelists.txt
set (BIN_DIR "${CMAKE_CURRENT_SOURCE_DIR}/bin")
add_subdirectory(xml/shrxml)
xml/CMakeLists.txt (AFTER the suggestion below)
set(CMAKE_BUILD_TYPE Release)
project(shrxml)
add_library(shrxml SHARED XML.c utils.c)
install(TARGETS shrxml LIBRARY DESTINATION ${BIN_DIR})
project(shrxmlSPCL)
add_dependencies(shrxmlSPCL shrxml)
add_library(shrxmlSPCL SHARED XMLSPCL.c)
target_link_libraries(shrxmlSPCL LINK_PUBLIC shrxml)
install(TARGETS shrxmlSPCL LIBRARY DESTINATION ${BIN_DIR})
I can get it to work, but I know there has to be a correct way to do this.
To get it to work, I:
comment out the xmlSPCL project
cmake ..
make shrxml
run make install so I can get shrxml.so in to the bin directory
un-comment out xmlSPCL
make (again)
make install (again)
What I want is to run make once, have the shrxml.so go into the bin dir so that when shrxmlSPCL is linked, it sees the dependent lib. Can that be done with the extra steps?
to make an example project run I had to make 3 things different
1.
target_link_libraries(shrxmlSPCL LINK_PUBLIC shrxml)
-> So neither lib nor .so as prefix/suffix
2.
add_dependencies(shrxmlSPCL shrxml)
-> somewhere below the add_library() having the dependency
3.
install(TARGETS shrxmlSPCL LIBRARY DESTINATION ${BIN_DIR})
-> add LIBRARY into your install command doc

CMake package dependencies handling

I am facing the current problem while using CMake:
I have libA, which I build using CMake and install it (in a custom directory, ~/install, using CMAKE_PREFIX_PATH) together with its exported targets and config (generated by CMake). The installed files look more or less like this:
~/install/lib/libA.so
~/install/lib/cmake/AConfig.cmake
~/install/lib/cmake/ATargets.cmake
I have libB, which links (privately) against libA:
find_package(A CONFIG REQUIRED)
add_library(B b.c)
target_link_libraries(B PRIVATE A)
I also install it together with its exported targets and config (generated by CMake).
Finally, I have an application which uses libB:
find_package(B CONFIG REQUIRED)
add_executable(app app.c)
target_link_libraries(app B)
The problem is that when the linker is executed, it will link against libB using the full path (~/install/lib/libB.so), but libA is only linked with -lA. As the libraries are not installed in any "standard" folder, it is not found (unless I manually add the folder using link_directories).
Am I doing anything wrong? What is the best solution to handle this case?
Thanks,

CMake subdirectory install/uninstall targets

I've got a project with two subdirectory projects (added with add_subdirectory), each with their own libraries, binaries and install/uninstall targets. So:
main_project
|
|--CMakeLists.txt
|--src/
|--CMakeLists.txt (with binary target, install()
|
|--project_a
|--CMakeLists.txt
|--src/
|--CMakeLists.txt (with library, install())
|
|--project_b
|--CMakeLists.txt
|--src/
|--CMakeLists.txt (with library, install())
I'd like for the top-level project (main_project) to automatically install the libraries a and b (included in main_project from target_link_libraries()). So, I'd like to be able to go:
cd main_project/build
cmake ..
make
sudo make install
and have the main_project binary and project_a/b libraries installed automatically. I've tried this:
main_project/src/CMakeLists.txt
...
install(FILES main project_a project_b DESTINATION bin
LIBRARY DESTINATION lib)
but a cmake .. results in
install TARGETS given target "project_a" which does not exist in this directory.
as expected.
I've also tried specifying a path:
main_project/src/CMakeLists.txt
...
install(FILES main ${CMAKE_SOURCE_DIR}/project_a/ ${CMAKE_SOURCE_DIR}/project_b DESTINATION bin
LIBRARY DESTINATION lib)
which also complains that project_a/b are not in this directory (also expected, I guess?)
I've also tried installing the libraries "manually" with the FILES option in install(), and that works just fine, but that seems very kludgy considering there are perfectly good install()s in the subprojects.
One additional issue: since project_a and project_b also have uninstall() custom targets, I can't add an uninstall target to the main_project without CMake complaining about the custom target already existing. When I try adding an uninstall directive to the top dir CMakeLists:
add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
But, since my project_a has an uninstall directive, I get:
CMake Error at CMakeLists.txt:37 (add_custom_target):
add_custom_target cannot create target "uninstall" because another
target with the same name already exists. The existing target is a
custom target created in source directory "/main_project/project_a".
See documentation for policy CMP0002 for more details.
So, how do I install and uninstall the necessary library files from my subproject alongside my main_project?
I found the problem. I am adding the subdirectory I want to install with EXCLUDE_FROM_ALL such that it doesn't build everything in the subdirectory, only the library I need. That flag seems to prevent the subdirectory install() from happening. Perhaps ExternalProject_Add is indeed the best way to go here...
Also, RE overriding custom targets, this worked for me: http://public.kitware.com/pipermail/cmake/2011-July/045269.html