I'm new in CMake enviroment. I have this project-structure tree:
/my_proj
│
├── deps
│ └── my_dep
│ └── CMakeLists.txt
├── src
│ └── main.cpp
└── CMakeLists.txt
Where my_dep is a git submodule used as dependency for my_proj project.
Usually I compile separatly these two entities, compiling first the library my_dep and then linking it to my_proj exe.
cd my_proj/deps/my_dep
cmake . && make
...compiling library...
cd my_proj
cmake . && make
...compiling exe and linking the above lib...
Now I would like be able to compile both library than executable in once, with a single CMake command.
The /my_proj/CMakeList.txt file must contaign all needed commands to first compile the my_dep lib and generate the .a/.so file, and after this compile the my_proj exe and finaly link the lib with exe.
I want make this procedure in once, with only a make command, e.g.
cd my_proj
cmake . && make
...compile lib, compile exe and link lib to exe...
Can you give me a simple explanantion about make it possible?
Related
Say I have a simple hello world project in CMake that creates a binary under bin.
I build it with Conan using the latest CMake module.
In the conanfile.py, is this package method enough to announce the executable?
def package(self):
cmake = CMake(self)
cmake.install()
Then, if I want to build the project and run the executable locally, but in Conan's context, which commands should I type?
The package method you've defined will use the installation structure defined by cmake.install() to define the package structure. For example, if your cmake.install() method installs binaries to the bin directory, the bin directory will be present in the package folder in your conan cache, i.e. ~/.conan/data/<package>/<version>/<user>/<channel>/package/<package_id>/bin.
This alone is enough to run the executable locally - you can execute it from the above path, put it onto your PATH - whatever you need. It's not convenient though. To add some convenience, you can use the VirtualRunEnv generator to consume executables. To illustrate with cmake:
$ conan install cmake/3.22.4# --build=missing -g VirtualRunEnv
This will install cmake 3.22.4 into your local cache, and generate the following files in your cwd:
.
├── conanrunenv-release-x86_64.sh
├── conanrun.sh
├── deactivate_conanrunenv-release-x86_64.sh
└── deactivate_conanrun.sh
You can use this in the same way you would a python virtual environment:
$ source conanrun.sh
$ which cmake
/home/user/.conan/data/cmake/3.22.4/_/_/package/5c09c752508b674ca5cb1f2d327b5a2d582866c8/bin/cmake
And to restore the environment:
$ source deactivate_conanrun.sh
Restoring environment
$ which cmake
/usr/bin/cmake
The second method is to use the deploy generator:
$ conan install cmake/3.22.4# --build=missing -g deploy
This will grab cmake and all of it's dependencies from the conan cache and dump them to your cwd. After running this command, the directory looks like the following:
.
├── cmake
│ ├── bin
│ │ ├── ccmake
│ │ ├── cmake
│ │ ├── cpack
│ │ └── ctest
│ ├── licenses
│ │ └── Copyright.txt
│ └── share
│ ├── aclocal
│ ├── bash-completion
│ ├── cmake-3.22
│ ├── emacs
│ └── vim
├── deploy_manifest.txt
└── openssl
├── bin
│ ├── c_rehash
│ └── openssl
├── include
│ └── openssl
├── lib
│ ├── cmake
│ ├── libcrypto.a
│ └── libssl.a
└── licenses
└── LICENSE
You can then move this wherever you need to and put it on your system PATH if you so desire. The same principle would apply to your package - create the recipe in the local cache, and use generators to consume it.
To illustrate:
Place your package in the conan cache
$ conan create .
Consume it using VirtualRunEnv
$ conan install mypkg/0.1.0#user/channel --build=missing -g VirtualRunEnv
Consume it using deploy
$ conan install mypkg/0.1.0#user/channel --build=missing -g deploy
Instead of issuing conan install commands above, you can also list your package as a requirement in a conanfile.txt or conanfile.py for a consumer package, i.e. for a conanfile.py:
def requirements(self):
self.requires(mypkg/0.1.0)
self.requires(someotherpkg/1.2.0)
And then you can use the virtual environment generators to collect environment information for all dependencies. In the directory containing the conanfile.py:
$ conan install . -g VirtualRunEnv
Hope this helps.
References:
VirtualRunEnv generator
deploy generator
Mastering Conan Virtual Environments
virtualrunenv generator (deprecated, I believe)
Conan generators
I use CMake for my C++ projects and I like to have my dependencies as Git submodules inside a third-party folder so I can have easy access to the code and the possible CMake targets I can link with.
.
├── CMakeLists.txt
├── src
│ └── main.cpp
└── third-party
└── CMakeSubmodule # OK
└── CMakeLists.txt # OK
My root CMakeLists.txt would typically contain :
add_subdirectory(src)
add_subdirectory(third-party/CMakeSubmodule)
target_link_libraries(myTarget PRIVATE SubmoduleTarget)
Now, I want to add a submodule that only uses premake :
.
├── CMakeLists.txt
├── src
│ └── main.cpp
└── third-party
└── PremakeSubmodule # !
└── premake5.lua # !
How would you do to simply add the submodule as a dependency ?
Do I have to manually convert all premake files to CMakeLists.txt ?
A convenient solution would allow to directly link to a target as follow, so I don't have to manually set the correct include directories and link to the lib files :
target_link_libraries(myTarget PRIVATE PremakeTarget) # Would be great
Because this is the standard structure of a ROS workspace (robotics framework) I have the following two directories:
ros/
|── DIR_A
│ ├── CMakeLists.txt
│ ├── package.xml
│ ├── README.md
│ ├── setup.py
│ └── src
│ ├── some_code.cpp
|── DIR_B
│ ├── CMakeLists.txt
│ ├── package.xml
│ ├── README.md
│ ├── setup.py
│ └── src
│ ├── some_other_code.cpp
I am trying to add a custom target called clean_compiled that will run the make clean target of a specific external project (already works). But I also need to add a custom command to this clean target in the CMakeLists of another directory. This is what I have:
First CMakeLists.txt:
# We add the custom target
add_custom_target(clean_compiled
COMMENT "Cleaning compilation files in ${SOME_DESTDIR}"
COMMAND $(MAKE) clean PATH=${SOME_DESTDIR}
WORKING_DIRECTORY ${SOME_WORKING_DIRECTORY}
)
Second CMakeLists.txt:
# We try to add a custom command to this custom target
add_custom_command(TARGET clean_compiled
COMMENT "Cleaning compilation files in ${ANOTHER_DESTDIR}"
WORKING_DIRECTORY ${ANOTHER_WORKING_DIRECTORY}
COMMAND $(MAKE) clean PATH=${ANOTHER_DESTDIR}
)
When I run make clean_compiled for the whole repository, I get this warning:
TARGET 'clean_compiled' was not created in this directory.
This warning is for project developers. Use -Wno-dev to suppress it.
And the custom_command is never called.
Is there any way to link the custom command to the target in the other directory without causing circular dependencies?
add_custom_command is pretty clear that it only works with targets in the same directory. There is no way around this. So the second rule cannot be a custom command and needs to be a custom target, for example called clean_another_dest_dir.
https://discourse.cmake.org/t/create-target-that-only-runs-other-target/885/6
You can use add_dependencyto make custom targets depend on other custom targets and make them run, add_dependencies(clean_another_dest_dir clean_compiled), but that isn't always what you want.
Another option is a custom target that runs all the other custom targets.
add_custom_target(clean_all_dir
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR } --target clean_compiled
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR } --target clean_another_dest_dir
)
TLDR
I want to build the LLVM project monorepo as a subdirectory to a larger CMake project. But the usual paradigm of add_subdirectory(llvm-project/llvm) doesn't give the desired results. How can I add LLVM to my CMake project so that building the project also builds LLVM?
Background
I have project tree that looks like this (some files and subdirectories omitted for brevity) :
.
├── build/
├── CMakeLists.txt
├── cunit/
│ ├── CUnit/
│ │ └── CMakeLists.txt
│ └── CMakeLists.txt
├── hayai/
│ └── CMakeLists.txt
├── install/
├── llvm-project/
│ ├── clang/
│ ├── clang-tools-extra/
│ ├── compiler-rt/
│ ├── debuginfo-tests/
│ ├── libcxx/
│ ├── libcxxabi/
│ ├── libunwind/
│ ├── lld/
│ ├── lldb/
│ ├── llvm/
│ │ └── CMakeLists.txt
│ ├── openmp/
│ └── polly/
└── mylib/
└── CMakeLists.txt
As you can see, I have four subdirectories, all of which are CMake projects in their own right, and all of which build individually with no problems. Both CUnit and Hayai are unmodified. Mylib is the product of my research, and uses CUnit and Hayai as git submodules/dependencies. I have also modified the LLVM Project monorepo to use Mylib for instrumentation as part of my research, but it builds on its own. I would like to unify all four of these subprojects as one CMake-driven build.
The content of the top-level CMakeLists.txt is:
cmake_minimum_required(VERSION 3.2)
project (myproject)
set(CMAKE_BUILD_TYPE Debug)
add_subdirectory(cunit/CUnit)
add_subdirectory(hayai)
add_subdirectory(mylib)
add_subdirectory(llvm-project/llvm)
Problem
When I try to generate the build using the following command:
cd build
cmake .. -DCMAKE_INSTALL_PREFIX=../install -DCMAKE_BUILD_TYPE=Debug -DBUILD_HAYAI_SAMPLES=false -DBUILD_HAYAI_TESTS=false
I get an error from CMake once it recurses into the LLVM subproject (shortened for brevity):
-- LLVM host triple: x86_64-unknown-linux-gnu
-- LLVM default target triple: x86_64-unknown-linux-gnu
-- Building with -fPIC
-- Constructing LLVMBuild project information
-- Linker detection: GNU ld
CMake Error: File ./llvm-project/llvm/include/llvm/module.modulemap.build does not exist.
CMake Error at ./llvm-project/llvm/include/llvm/CMakeLists.txt:7 (configure_file):
configure_file Problem configuring file
-- Targeting AArch64
-- Targeting AMDGPU
-- Targeting ARM
-- Targeting BPF
-- Targeting Hexagon
-- Targeting Lanai
-- Targeting Mips
-- Targeting MSP430
-- Targeting NVPTX
-- Targeting PowerPC
-- Targeting Sparc
-- Targeting SystemZ
-- Targeting X86
-- Targeting XCore
-- Configuring incomplete, errors occurred!
See also "./build/CMakeFiles/CMakeOutput.log".
See also "./build/CMakeFiles/CMakeError.log".
llvm-project/llvm/include/llvm/CMakeLists.txt contains:
add_subdirectory(IR)
add_subdirectory(Support)
# If we're doing an out-of-tree build, copy a module map for generated
# header files into the build area.
if (NOT "${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
configure_file(module.modulemap.build module.modulemap COPYONLY)
endif (NOT "${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
I checked the two files at the end of the output, but neither had messages relevant to the problem.
Questions
What does the error from CMake really mean? Why doesn't module.modulemap.build exist, or more accurately, why does it exist when building just LLVM?
How can I fix this so that my top level project can build all four subprojects?
Potentially Related
This StackOverflow question asks a similar question using a lot of the same keywords, but has a different task in mind: she/he wants to link to libraries from an existing LLVM build, not build LLVM itself.
Likewise this StackOverflow question and the accepted answer's reference to this LLVM documentation page is about embedding LLVM libraries out of tree into a standalone project. It's not quite what I want since I need to build my entire modified LLVM compiler toolchain.
This llvm-dev mailing list thread sounds like exactly what I'm doing, but the suggested answer doesn't work, as stated above.
What does the error from CMake really mean?
#Tsyvarev correctly identified that the problem was in fact that llvm-project/llvm/include/llvm/module.modulemap.build didn't exist. This was because I downloaded an archive of the project through Github, which appears to have excluded .build files by default. When cloning or forking the project, the missing files are present.
The problem is reproducible, but I don't know why Github behaves the way it does. That is beyond the scope of the question.
How can I fix this so that my top level project can build all four subprojects?
Using add_subdirectory(llvm-project/llvm) command in the top-level CMakeLists.txt file is sufficient, but you must also specify LLVM's options at generate time, of course.
I have a CMake-based project that consists of several sub-components, which can all be independently compiled and tested. The directory layout looks like this:
.
├── CMakeLists.txt
├── comp1
│ ├── CMakeLists.txt
│ ├── src
│ │ ├── foo.cc
│ │ └── foo.h
│ └── tests
│ ├── CMakeLists.txt
│ └── test_comp1.cc
└── comp2
├── CMakeLists.txt
├── src
│ ├── bar.cc
│ └── bar.h
└── tests
├── CMakeLists.txt
└── test_comp2.cc
I want to enable ctest, therefore in the root CMakeLists.txt I have include(CTest) and in the component-specific CMakeLists.txt files I have
if(BUILD_TESTING)
add_subdirectory(tests)
endif()
In compX/tests/CMakeLists.txt I have the code to compile the test and the add_test()command. The tests get successfully compiled and I can manually run them. However, if I call ctest, it returns
No tests were found!!!
After playing a bit with this, it turned out that if I move the add_subdirectory(tests) call to the root CMakeLists.txt like this:
if(BUILD_TESTING)
add_subdirectory(comp1/tests)
endif()
it works. But I find this quite ugly and messy, to put component-specific stuff into the root file.
Conversely, I tried to move the include(CTest) command one level down into the component-specific CMakeLists.txt. But ctest complains with this:
*********************************
No test configuration file found!
*********************************
Is there seriously no way to use ctest with a directory structure like above?
The CTest documentation isn't the clearest.
A project I'm working on has a similar directory structure composed of various units, and in each unit are src and tests subdirectories.
CMake documentation says to call "enable_testing()" at the top-level CMakeLists.txt file, and it further says this command will "enable CTest at the current directory and below." Which sounds recursive, right? Well it's not.
Every CMakeLists.txt must have enable_testing() called to enable automatic CTest discovery in that directory.
Thus, in your project, the toplevel CMakeLists.txt will need enable_testing(), then comp{1,2}/CMakeLists.txt will need it, and finally comp{1,2}/tests/CMakeLists.txt will need it.
Once you add those commands and rerun cmake, those directories will each contain a CTestTestfile.cmake file, which is what the ctest program will look for when it runs.