Multiple conanfile.py management - build

Let's say I have 2 different conanfile.py in a project and I'm calling conan install two times to install their dependencies. I'm having trouble while adding them to cmake.
If I use basic setup
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
it only includes latest one. Is it possible to include multiple conanbuildinfo.cmake files ?

If you have 2 completely separate projects, you can have 2 different conanfiles and put the generated files in different folders:
$ conan install conanfile1.py --install-folder=folder1
$ conan install conanfile2.py --install-folder=folder2
Then in your first project:
include(<...>/folder1/conanbuildinfo.cmake)
conan_basic_setup()
And in your second project:
include(<...>/folder2/conanbuildinfo.cmake)
conan_basic_setup()
You would need to define some consistent convention to locate the generated files for each project.
Note, however, that if the different modules are intended to use together, like linked together lately, if you don't use the same dependencies and same versions, you will probably get linking or runtime errors in your global application. If the modules are related and you want to use the same versions of the dependencies, then you definitely want to use just 1 conanfile with all dependencies defined in it.
Note that there are different ways to define the specific dependencies that you want, even if you use only 1 conanfile:
You can use the TARGETS of the cmake generator:
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(TARGETS)```
add_library(mylib1 ... <sources>)
target_link_libraries(mylib1 PUBLIC CONAN_PKG::Dep1 CONAN_PKG::Dep2)
add_library(mylib2 ... <sources>)
target_link_libraries(mylib2 PUBLIC CONAN_PKG::Dep3 CONAN_PKG::Dep4)
The cmake_find_package generators also generate one findXXXX.cmake file for each package in the dependency graph. You can use the find_package(XXXX) and later the results, specifying different dependencies. The cmake_find_package_multi generator is recommended.

Related

CMake phony target which duplicates another target

I am trying to "duplicate" a target in my CMake file without maintaining 2 targets and all it's dependencies.
For example I have a main target MyBigLibrary
add_library(MyBigLibrary STATIC "")
target_compile_definitions(MyBigLibrary PRIVATE definitions..)
target_include_directories(MyBigLibrary PUBLIC public_directories..)
target_include_directories(MyBigLibrary PRIVATE private_directories..)
target_link_libraries(MyBigLibrary INTERFACE libraries..)
...
...
target_sources(MyBigLibrary ..source files..)
What I am trying to achieve is to have a identical copy of MyBigLibrary target (e.g. MyBigLibraryModified) which then I can feed to external script via add_custom_command.
I know there is way to have 2 targets, but then you have maintain 2 targets and all of it's dependencies.
Is there a way to have a phony target, e.g MyBigLibraryModified which is built only MyBigLibrary, and inherits INTERFACE flags as a dependencies?
When I wanted to create two different libraries containing the same compiled objects but with different features, I used the OBJECT library type containing all the source files, then I created two different libraries that listed the OBJECT target in their target_link_libraries.
The OBJECT library in CMake is still not fully correct, even after years of waiting for it to be enhanced, but it works mostly OK in most situations these days.
See the documentation for more info.
Comments under question:
... Are you trying strip symbols from release version of your target? –
Marek R
#MarekR that is correct. – pureofpure
So you are doing that wrong. You do not need (and you should not have) separate target for stripped version of your library/application.
For stripped version build proves is just a bit different.
One way to do it is just do:
$ cmake --install . --prefix PathWithResultsWithSybols .....
$ cmake --install . --prefix PathWithStripedResults --strip ....
See cmake doc

How to use export custom target with CMake?

I'm trying to export all of the dependent targets of an engine I've been developing with export command. Everything works fine with dependencies, but when I call the command with main "Nabla" target, I get a following error:
CMake Error in CMakeLists.txt:
export called with target "Nabla" which requires target "openssl_build"
that is not in any export set.
The problem is that the openssl_build is a custom target and I have no clue how to avoid this error, because when I try to export the target I get another error telling me that
-- Using static CRT ON
CMake Error at 3rdparty/CMakeLists.txt:556 (export):
export given custom target "openssl_build" which may not be exported.
the following commit contains my changes to the engine in reference to export command
The custom target generating the error is here
I wonder if I could set a cmake property for the openssl_build to make it work, but I have been looking for useful properties in cmake docs and could not find anything
Thank you in advance!
This usually happens when you use add_subdirectory to consume library.
When you add add_subdirectory, CMake will consider, for example, the whole openssl project become part of your project. They are not separable if they are the same project.
If you build openssl as part of your project, it's very doubting that your project will run properly without also having openssl installed, let alone users consuming your package!
You could simply add the openssl libraries you depend on to the export set:
install(TARGETS openssl_build EXPORT NablaTargets)
But that's not the proper way.
The proper way would be to use a package manager, such as vcpkg to install the dependencies for you.
First, replace the add_subdirectory by a find_package and a link:
find_package(OpenSSL REQUIRED)
target_link_libraries(Nabla PUBLIC OpenSSL::SSL OpenSSL::Crypto)
Create vcpkg.json with this content:
{
"name": "nabla",
"version-string": "0.1",
"dependencies": [
"openssl"
]
}
And when you use cmake, add the argument -DCMAKE_TOOLCHAIN_FILE=/opt/vcpkg/scripts/buildsystems/vcpkg.cmake (or where you installed it) and let the package manager do the work for you.
Remember that when you use a new toolchain file, you must re-create a new build directory since it cannot be added after creating it.

How do I export a target, then use it in another project via ExternalProject?

I have a CMake project named proj1, which I want to use as an external project in another project, proj2. Now, the (relevant) command in proj1's CMakeLists.txt is:
install(
TARGETS proj1
ARCHIVE
DESTINATION lib
EXPORT proj1_library
INCLUDES DESTINATION include
CONFIGURATIONS Release RelWithDebugInfo
)
and I want to use this static library in proj2, without explicitly "guessing" where it's installed to be proj1. I want to be able to get obtain this target from proj1 (which I obtain using ExternalProject), then use it - directly or indirectly - in add_target_libraries() commands.
How should I do that? And - do I only need to make changes to proj2 or also to proj1's CMakeLists.txt?
Exporting the targets is the right approach.
To support this, proj1 would have to generate a proj1Config.cmake in both its build tree and also in the install tree (so that a development package for proj1 can be used as a SDK [1])
I suggest you read the following section of the CMake documentation, it covers the different concepts and provides an example. See https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#creating-packages
[1] SDK: https://en.wikipedia.org/wiki/Software_development_kit

Isolating gitsubmodule projects in CMake

I'm trying to manage my C++ project dependencies using CMake and gitsubmodules. I'm following the layout described here: http://foonathan.net/blog/2016/07/07/cmake-dependency-handling.html and it's worked really well for me on smaller projects. But I've started to use it on much larger projects and I'm hitting some issue with CMake.
My current setup
All my external build dependencies are in a contrib/ subfolder inside my main project. Each is a submodule and has its own separate directory.
/contrib
- /eigen
- /curl
- /leapserial
- /zlib
- /opencv
etc.
The contrib/CMakeListst.txt simply initializes the submodule and adds the subdirectory for each external dependency
# EIGEN
execute_process(COMMAND git submodule update --recursive --init -- eigen
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
# options..
add_subdirectory(eigen EXCLUDE_FROM_ALL)
# CURL
execute_process(COMMAND git submodule update --recursive --init -- curl
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
# Initialize cache with CMake build options..
add_subdirectory(curl EXCLUDE_FROM_ALL)
# LEAP SERIAL
execute_process(COMMAND git submodule update --recursive --init -- leapserial
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
# Initialize cache with CMake build options..
add_subdirectory(leapserial EXCLUDE_FROM_ALL)
# ZLIB
execute_process(COMMAND git submodule update --recursive --init -- zlib
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
# Initialize cache with CMake build options..
add_subdirectory(zlib EXCLUDE_FROM_ALL)
# OPENCV
execute_process(COMMAND git submodule update --recursive --init -- opencv
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
# Initialize cache with CMake build options..
add_subdirectory(opencv EXCLUDE_FROM_ALL)
This setup has worked fantastically for me:
It's system/packagemanager independent. You don't need to install any libraries to get started developing
I can maintain the exact versions of my dependencies by setting the submodule to a particular commit. There are no surprises with some external library breaking your build
Adding the libraries to my build in the root CMakeListst.txt is trivial. Since I have the target available I just have something like
add_executable(someProjectImWorkingOn
${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp )
target_link_libraries(someProjectImWorkingOn
opencv_world
eigen
zlib
etc.)
when you hook up an existing library target to your own target executable/library CMake will automatically (through the target interface) add include directories to your target and add any other necessary options the library target requires for it to be used
I can pick a toolchain/compiler-option/build-type in the root CMakeLists.txt and it'll propogate to all the subprojects (I need to build for multiple systems. So this is a big big deal)
Since it's all in one "mega-project" it makes it very easy to hook up to rtags/kdevelop/clion to navigate not on your own code, but also the library code
Some issues that I can't resolved:
1
Subdirectories will define targets with the same name. In the example I gave, both Eigen OpenCV as well as another library define an 'uninstall' target
I tried to update the
add_subdirectory(blah)
to
add_subdirectory(blah EXCLUDE_FROM_ALL)
but this doesn't fix the issue for some reason
Enabling the variable ALLOW_DUPLICATE_CUSTOM_TARGETS kinda works.. but this is a hack, only work with Make files, and the libraries are essentially still "mixing" so it's still an issue
2
The second issue came up in LeapSerial but illustrates a bigger issue. The project no longer knows it's own name. LeapSerial tried to determine the version of LeapSerial, but when it asks for the project version it's getting the root project version. Ie. when cmake code in a subproject asks for "what project am I in" it's getting the root project, and not the immediate project it's in.
So again, the parent "namespace"s are leaking everywhere. This is bound to create more and more issues down the line. I need to the submodules to be self-contained
Is there are a cleaner solution?
ExternalProjectAdd might solve some of these problems, but has a lot more issues of its own. It's a real non-starter b/c it doesn't do most of what I've listed. The central issue is that it doesn't expose the sub-project's targets - and just vomits back variables that you then have to juggle
As the asker said in the comments, they resolved their issue by using the Hunter package manager. The rest of this answer is about actually answering the question as posed.
Concerning your first issue with target name clashes when using add_subdirectory-based approaches to using dependencies, a very similar (or essentially the same?) question has also since been asked here: How to avoid namespace collision when using CMake FetchContent?. When the clashes are between targets from different project dependencies, there's nothing you can do right now except politely ask the project maintainers to consider modifying their non-import/export target names to be namespaced like.
For example, for a library target, that might look like:
add_library(projectname_targetnamepart)
add_library("importexportnamespacename::targetnamepart" ALIAS projectname_targetnamepart)
set_target_properties(projectname_targetnamepart PROPERTIES EXPORT_NAME targetnamepart)
set_target_properties(projectname_targetnamepart PROPERTIES OUTPUT_NAME targetnamepart)
install(TARGETS projectname_targetnamepart EXPORT projectname_targets ...)
install(EXPORT projectname_targets NAMESPACE "importexportnamespacename::" ...)
There's a Kitware issue ticket by Craig Scott proposing a CMake feature for Project-level namespaces. Here's an excerpt:
A common problem when pulling in subprojects using add_subdirectory() is that target names must be unique, but different subprojects might try to use the same target name, which results in a name clash. This issue proposes to introduce the concept of a project namespace to address this and related name uniqueness problems (this is the primary goal of this issue).
Sometimes the upstream maintainer will just decline to support the add_subdirectory / FetchContent use-case. That's the case with OpenCV, as shown in this issue ticket (#16896). As for eigen, there's an open ticket that hasn't had any activity in a while (#1892).
Concerning your second issue, there's not enough detail in your question post to confidently troubleshoot. What is LeapSerial? Are you referring to the leapmotion/leapserial GitHub repo? What version and what commit are you referring to? At the latest commit before the time of your question post, 41515db, it's not immediately obvious what's wrong.
Variables in CMake are scoped by directory, so even if a project is added by add_subdirectory and doesn't used the <PROJECT-NAME>_VERSION variable and instead uses the more general PROJECT_VERSION variable, it should be okay. It just shouldn't attempt to use the CMAKE_PROJECT_VERSION variable to get its own version, since that one is fixed to refer to the top-level project's version.

preferred cmake project structure

I would like to have the following structure A -> B -> C, where:
C is boilerplate code, wrappers for third-party libraries, very
basic code etc.
B is the common classes, functions and data
structures specific to the project's domain.
A is the project itself.
I would like to make it easy to reuse C or B(+C) in future in my other projects. In addition, I have the following requirements:
As all three projects are in-progress, I would like to have an ability to build C, C+B and C+B+A in one shot.
I would prefer the static linkage over dynamic, so that C and C+B would be static libraries, and C+B+A would be the executable
I would like to keep cmake lists and config files simple and clean. Examples which I found in the official wiki and over the internet are pretty big and monstrous.
It would be great if it won't require changing more than a couple of lines if I'd change the locations of A, B or C in the filesystem.
All these three components are using google-test, but I'm not sure if it is important for the project layout.
I am pretty new to cmake and I don't even understand is it better to write XXXConfig.cmake or FindXXX.cmake files. Also, I am not sure, how should I pass relative paths from subcomponent to the parent component using X_INCLUDE_DIRS.
First I have to admit that I agree with #Tsyvarev. Your CMake environment should fit to your processes/workflow and should take project sizes and team structure into account. Or generally speaking the environment CMake will be used in. And this tends to be - in a positive way - very alive.
So this part of your question is difficult to answer and I'll concentrate on the technical part:
CMake has to know the location of the dependencies - relative or absolute - by
having a monolithic source tree (the one you don't want anymore)
CMake share library with multiple executables
CMake: How to setup Source, Library and CMakeLists.txt dependencies?
a common directory location for includes/libraries/binaries
Custom Directory for CMake Library Output
cmake install not installing libraries on windows
getting the paths via config files/variable definitions
How can I get cmake to find my alternative boost installation?
How to add_custom_command() for the CMake build process itself?
using registration in or installation from a database provided on the host
Making cmake library accessible by other cmake packages automatically
cmake wont run build_command in ExternalProject_Add correctly
To keep your CMake files as simple as possible I would recommend to group your CMake code into separate dedicated files:
Prefer toolchain files over if(SomeCompiler) statements
Move common/repeating code parts as function() bodies into a shared CMake include file
Move complex non-target specific code parts into their own (CMake) script files
Example Code
Since you have specifically asked for the find_package() variant, taking Use CMake-enabled libraries in your CMake project and the things listed above:
MyCommonCode.cmake
cmake_policy(SET CMP0022 NEW)
function(my_export_target _target _include_dir)
file(
WRITE "${CMAKE_CURRENT_BINARY_DIR}/${_target}Config.cmake"
"
include(\"\$\{CMAKE_CURRENT_LIST_DIR\}/${_target}Targets.cmake\")
set_property(
TARGET ${_target}
APPEND PROPERTY
INTERFACE_INCLUDE_DIRECTORIES \"${_include_dir}\"
)
"
)
export(
TARGETS ${_target}
FILE "${CMAKE_CURRENT_BINARY_DIR}/${_target}Targets.cmake"
EXPORT_LINK_INTERFACE_LIBRARIES
)
export(PACKAGE ${_target})
endfunction(my_export_target)
C/CMakeLists.txt
include(MyCommonCode.cmake)
...
my_export_target(C "${CMAKE_CURRENT_SOURCE_DIR}/include")
B/CMakeLists.txt
include(MyCommonCode.cmake)
find_package(C REQUIRED)
...
target_link_libraries(B C)
my_export_target(B "${CMAKE_CURRENT_SOURCE_DIR}/include")
A/CMakeLists.txt
include(MyCommonCode.cmake)
find_package(B REQUIRED)
...
target_link_libraries(A B)
This keeps all 3 build environments separate, only sharing the relatively static MyCommonCode.cmake file. So in this approach I have so far not covered your first point, but would recommend the use of a external script to chain/trigger your build steps for A/B/C.