I've been trying to use clang-modernize with CMAKE_EXPORT_COMPILE_COMMANDS as recommended in the help of this tool.
With this option cmake generates a JSON file containing compile info like include paths (see also).
This variable is accepted on the command line of cmake,
but cmake --help-variable CMAKE_EXPORT_COMPILE_COMMANDS doesn't work (which is coherent with this mailing list posting).
Has someone any idea on how to use it?
I could also use it with cppcheck.
Some more info
I've discovered on a clang developer forum that this cmake feature is not available on all generators. This might change in the future, in the mean time my question remains and I will try too see what happen if I use other generators than Visual Studio.
I suggest setting
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
in the CMakeList.txt
As of CMake 3.5 the CMAKE_EXPORT_COMPILE_COMMANDS option is supported by the Ninja and Makefiles generators.
That means to generate a JSON compile database one has to select a generator that supports it.
For example on UNIX just:
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 /path/to/src
(as it uses the makefile generator there, by default)
Otherwise you can explicitly specify a generator like this:
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 /path/to/src -G Ninja
Or:
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 /path/to/src -G 'Unix Makefiles'
Or another makefiles variant that your cmake supports - a list of supported generators is included in the output of cmake --help.
Note that the compile database JSON file is generated at cmake execution time - not at compile time. Also, with recent clang versions (e.g. clang >= 3.8), clang-modernize was merged into clang-tidy.
I too was not able to get to work on the Visual Studio generator.
It did, however, work using the "NMake Makefiles" generator.
C:\work\build>cmake -G "NMake Makefiles" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..
The first one you use CMAKE_EXPORT_COMPILE_COMMANDS ON in your CMakelists.txt
Or run CMake with following parameters:
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ..
1.Option:
Here is a simple source and build tree to make it clear.
.
├── build
├── cars
│ ├── car.cpp
│ ├── car.h
│ └── CMakeLists.txt
├── CMakeLists.txt
└── main.cpp
main.cpp
#include <iostream>
#include "car.h"
int main (int argc, char *argv[])
{
std::cout << "car - main function" << std::endl;
showCarName();
return 0;
}
CMakeLists.txt:
cmake_minimum_required(VERSION 3.20)
project(Cars
VERSION 0.1
HOMEPAGE_URL "github/alitokur"
LANGUAGES CXX
)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_executable(carApp main.cpp)
add_subdirectory(cars)
target_link_libraries(carApp PRIVATE cars)
cars/CMakeLists.txt
add_library(cars OBJECT
car.cpp
)
target_include_directories(cars PUBLIC .)
And that's all, target link directories allow main.cpp to include the cars.h file without providing a relative path. You should use set(CMAKE_EXPORT_COMPILE_COMMANDS ON) after the project() definition because sometimes other tools override this setting and that's why you can't see compile_commands.json.
CMake 3.17
As of CMake 3.17 you can now set CMAKE_EXPORT_COMPILE_COMMANDS as an environment variable.
The default value for CMAKE_EXPORT_COMPILE_COMMANDS when there is no explicit configuration given on the first run while creating a new build tree. On later runs in an existing build tree the value persists in the cache as CMAKE_EXPORT_COMPILE_COMMANDS.
This is the best approach since you don't have to pollute project code or remember to set it individually for each project.
# Set this in your .bashrc or whatever environment you choose to set env variables
export CMAKE_EXPORT_COMPILE_COMMANDS=1
CMake 3.5
The second best approach is to pass CMAKE_EXPORT_COMPILE_COMMANDS as a cache variable when configuring the project.
cmake -S . -B build -D CMAKE_EXPORT_COMPILE_COMMANDS=1
I prefer the new CMake 3.17 approach, since the 3.5 approach is easy to forget.
Related
I have a project that depends on Intel's oneTBB. My project is structured as follows:
external/
| - CMakeLists.txt
| - oneTBB/ (this is a git submodule)
| - ...
include/
lib/
include/
CMakeLists.txt
I currently get things to compile by manually building oneTBB and installing it inside a prefix directory located at external/oneTBB/prefix by running the following (bash) commands:
cd oneTBB
mkdir -p prefix
mkdir -p build
cd build
cmake -DCMAKE_INSTALL_PREFIX=../prefix -DTBB_TEST=OFF ..
cmake --build .
cmake --install .
I then simply include and link using this prefix. (I got this from following the oneTBB READMEs)
While this works without issue, I'm currently trying to clean up my CMake such that its easier to build on Windows as well. Ideally, I'm looking to get to a point where I can simply run:
mkdir build
cd build
cmake ..
cmake --build .
and my project will build itself and all dependencies.
I got this working with other dependencies such as glfw and eigen by simply adding (to the CMakeLists.txt in external/:
add_subdirectory(glfw)
add_subdirectory(eigen)
But adding add_subdirectory(oneTBB) throws a LOT of warnings, starting with:
CMake Warning at external/oneTBB/CMakeLists.txt:116 (message):
You are building oneTBB as a static library. This is highly discouraged
and such configuration is not supported. Consider building a dynamic
library to avoid unforeseen issues.
-- TBBBind build targets are disabled due to unsupported environment
-- Configuring done
CMake Warning (dev) at external/oneTBB/src/tbb/CMakeLists.txt:15 (add_library):
Policy CMP0069 is not set: INTERPROCEDURAL_OPTIMIZATION is enforced when
enabled. Run "cmake --help-policy CMP0069" for policy details. Use the
cmake_policy command to set the policy and suppress this warning.
INTERPROCEDURAL_OPTIMIZATION property will be ignored for target 'tbb'.
This warning is for project developers. Use -Wno-dev to suppress it.
I have no need to build oneTBB as a static library.
Am I doing something wrong in my attempt? Really all I need is for oneTBB to be built as a dynamic library and placed somewhere I can link it to (without installing it on the system overall)
Similar question:
I am also including the METIS library which depends on GKlib. Currently I'm doing this in a similar way to what I did for oneTBB where I manually build each using the following script:
# Setup the GKlib library:
cd GKlib
mkdir -p prefix
mkdir -p build
cd build
cmake -DCMAKE_INSTALL_PREFIX=../prefix ..
cmake --build . -j
cmake --install .
cd ../../
# Setup the METIS library:
cd METIS
mkdir -p prefix
make config prefix=../prefix gklib_path=../GKlib/prefix #(GKLib path is done from root, install path done relative to build)
make install -j
cd ../
When I try to add them using:
add_subdirectory(GKlib)
add_subdirectory(METIS)
it throws errors that METIS cannot find GKlib:
CMake Error at external/METIS/CMakeLists.txt:50 (add_subdirectory):
add_subdirectory given source "build/xinclude" which is not an existing
directory.
While I recognize this is a separate issue, I figured to include it here as it is related to my issues with add_subdirectory()
Many projects expect that you invoke CMake on them separately instead of adding them into an existing project with add_subdirectory. While there might be a way to make add_subdirectory work with oneTBB, there is an easier way.
CMake has a function that allows you to download, build, and install external projects at build time: ExternalProject_Add.
Here's an example for spdlog, taken straight from one of my own projects:
# project_root/thirdparty/spdlog/CMakeLists.txt
string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_UPPER)
ExternalProject_Add(spdlog-project
GIT_REPOSITORY https://github.com/gabime/spdlog
GIT_TAG edc51df1bdad8667b628999394a1e7c4dc6f3658
GIT_SUBMODULES_RECURSE ON
GIT_REMOTE_UPDATE_STRATEGY CHECKOUT
INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/install"
LIST_SEPARATOR |
CMAKE_CACHE_ARGS
"-DCMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER}:STRING=${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER}}"
"-DCMAKE_C_FLAGS_${CMAKE_BUILD_TYPE_UPPER}:STRING=${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE_UPPER}}"
"-DCMAKE_EXE_LINKER_FLAGS_${CMAKE_BUILD_TYPE_UPPER}:STRING=${CMAKE_EXE_LINKER_FLAGS_${CMAKE_BUILD_TYPE_UPPER}}"
"-DCMAKE_SHARED_LINKER_FLAGS_${CMAKE_BUILD_TYPE_UPPER}:STRING=${CMAKE_SHARED_LINKER_FLAGS_${CMAKE_BUILD_TYPE_UPPER}}"
"-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}"
"-DCMAKE_INSTALL_PREFIX:STRING=<INSTALL_DIR>"
"-DSPDLOG_BUILD_EXAMPLE:BOOL=OFF"
)
add_library(ext-spdlog INTERFACE)
add_dependencies(ext-spdlog spdlog-project)
ExternalProject_Get_property(spdlog-project INSTALL_DIR)
target_include_directories(ext-spdlog SYSTEM INTERFACE "${INSTALL_DIR}/include")
target_link_directories(ext-spdlog INTERFACE "${INSTALL_DIR}/lib")
target_link_libraries(ext-spdlog INTERFACE spdlog$<$<CONFIG:Debug>:d>)
After that, my project simply links against the created library target:
target_link_libraries(my_project ext-spdlog)
To adapt this for oneTBB, you have to switch out the repository URL and commit hash, and add your own CMake definitions (i.e. "-DTBB_TEST=OFF"). Depending on how oneTBB has its include and library directories set up, you may also have to change the target_include_directories and/or target_link_directories lines. I haven't looked this up yet, but I'm sure you can figure it out.
This works regardless of whether the external project is built as a static or shared library. You shouldn't use git submodules, though - instead, let CMake do the downloading. (It'll only download and build once; subsequent builds will not re-build the external project if it's already built and up-to-date.)
I have no need to build oneTBB as a static library. Am I doing something wrong in my attempt? Really all I need is for oneTBB to be built as a dynamic library and placed somewhere I can link it to (without installing it on the system overall)
All your diagnostic messages indicate that it's actually being configured to be built as a static library, and additional clues point to the probability that you've set BUILD_SHARED_LIBS to false in the scope where you add_subdirectory(oneTBB).
CMake Warning at external/oneTBB/CMakeLists.txt:116 (message):
You are building oneTBB as a static library. This is highly discouraged
and such configuration is not supported. Consider building a dynamic
library to avoid unforeseen issues.
If you look in oneTBB's CMakeLists.txt file, you'll the following:
if (NOT DEFINED BUILD_SHARED_LIBS)
set(BUILD_SHARED_LIBS ON)
endif()
if (NOT BUILD_SHARED_LIBS)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
message(WARNING "You are building oneTBB as a static library. This is highly discouraged and such configuration is not supported. Consider building a dynamic library to avoid unforeseen issues.")
endif()
And then right after that, you get
-- TBBBind build targets are disabled due to unsupported environment
The corresponding section of oneTBB's CMakeLists.txt file is:
if (TBB_FIND_PACKAGE OR TBB_DIR)
...
else()
if (APPLE OR NOT BUILD_SHARED_LIBS)
message(STATUS "TBBBind build targets are disabled due to unsupported environment")
else()
add_subdirectory(src/tbbbind)
endif()
...
Both of these clues indicate that in the variable scope at which you add_subdirectory(oneTBB), BUILD_SHARED_LIBS is set to a falsy value.
Set BUILD_SHARED_LIBS it to a truthy value (Ex. 1, TRUE, YES, ON, etc.) before doing add_subdirectory(oneTBB) and then restore the previous value afterward.
Ex.
set(BUILD_SHARED_LIBS_TEMP "${BUILD_SHARED_LIBS}")
set(BUILD_SHARED_LIBS YES)
add_subdirectory(oneTBB)
set(BUILD_SHARED_LIBS "${BUILD_SHARED_LIBS_TEMP}")
unset(BUILD_SHARED_LIBS_TEMP)
I have followed the opencv doc for creating my own bindings.
I run the file gen2.py which generated some header files:
./
../
pyopencv_generated_enums.h
pyopencv_generated_funcs.h
pyopencv_generated_include.h
pyopencv_generated_modules_content.h
pyopencv_generated_modules.h
pyopencv_generated_types_content.h
pyopencv_generated_types.h
pyopencv_signatures.json
How should I build this?
I tried running cmake CMakeLists.txt directly in /opencv/modules/python but some defines were not found.
and I tried on re-building running cmake CMakeLists.txt in /opencv/ , where I got:
FATAL: In-source builds are not allowed.
You should create a separate directory for build files.
I think both approaches were quite wrong, but I haven't found any doc explaining how to build using the generated headers.
I'm using opencv 4.5.5 which I cloned and built.
EDIT
I found this in /source/opencv/modules/python/bindings/CMakeLists.txt:
string(REPLACE ";" "\n" opencv_hdrs_ "${opencv_hdrs}")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/headers.txt" "${opencv_hdrs_}")
add_custom_command(
OUTPUT ${cv2_generated_files}
COMMAND "${PYTHON_DEFAULT_EXECUTABLE}" "${PYTHON_SOURCE_DIR}/src2/gen2.py" "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/headers.txt"
DEPENDS "${PYTHON_SOURCE_DIR}/src2/gen2.py"
"${PYTHON_SOURCE_DIR}/src2/hdr_parser.py"
# not a real build dependency (file(WRITE) result): ${CMAKE_CURRENT_BINARY_DIR}/headers.txt
${opencv_hdrs}
COMMENT "Generate files for Python bindings and documentation"
)
I guess I have to add the path to my headers in ${CMAKE_CURRENT_BINARY_DIR}/headers.txt just not sure how to get the value of CMAKE_CURRENT_BINARY_DIR
EDIT 2
As proposed by #berak, I tried CMAKE_EXTRA_MODULES_PATH=my/path
this seems to get me really close to what I need.
It compiles my sources and generates the .so files as libopencv_xxx.so and saves them in my /usr/local/lib
(when running nm on it I see my class and method)
BUT! when I import cv2 in a script I don't achieve to load my module.
I tried print(cv2.__dict__) and greped on it, but it's not there.
Any clue on how to add the compiled modules into my python-opencv installation?
There's not much documentation on how to create a bind (at least I only found this, which is very helpful but doesn't have all the information).
First, your module must use the following tree structure (I did everything with cmake):
.
src
└── modules
└── your_module
├── CMakeLists.txt
├── include
│ └── opencv2
│ └── your_module_bind_lib.hpp
└── src
└── your_module_bind_lib.cpp
An example of my CMakeLists.txt (this of course may change according to your project):
set(the_description "yourModule LIB")
ocv_define_module(your_module opencv_imgproc WRAP python)
include_directories(${OpenCV_INCLUDE_DIRS})
Then I cloned OpenCV with
git clone https://github.com/opencv/opencv.git
Make a build folder
mkdir wherever/build
And run the following command for cmake
cd wherever/build
cmake -DOPENCV_EXTRA_MODULES_PATH=/project_from_previous_tree/src/modules/ -D BUILD_EXAMPLES=OFF -D BUILD_opencv_apps=OFF -D BUILD_DOCS=OFF -D BUILD_PERF_TESTS=OFF -D BUILD_TESTS=OFF -D CMAKE_INSTALL_PREFIX=/usr/local/ your_opencv_location/opencv/
make -j8
make install
In that command the only "special" thing was DOPENCV_EXTRA_MODULES_PATH (thanks to #berak for the idea).
And then? what happens in python level?
Make sure your python installation actually points to the built opencv, or use something like:
import sys
sys.path.append('/usr/local/lib/python3.8/site-packages/cv2/python-3.8')
import cv2
where /usr/local/lib/python3.8/site-packages/cv2/python-3.8' is where the generated .so is located in my PC.
With this you will be able to use things like
cv2.my_cpp_function()
cv2.my_cpp_class.some_method()
...
Where my_cpp stuff was declared and defined in the module project following the doc and can "easily" have OpenCV typed objects as parameters.
Et voila, now you can use your c++ functions in python.
Notice that this solution does not do any modification to the opencv directory cloned from Git.
You're not supposed to run gen2.py manually, cmake will do this for you at some stage, internally.
since you seem to be on some linux, rather follow the build steps here, this will also generate python bindings, the gist of it is:
make a special "build folder" and cd into it (dont try to build in the src folder, you'll never be able to clean anything up)
run cmake <some args> path_to_src_folder (or better even - cmake-gui) , check if python3 shows up in the "To be build" section of the output
run make install
I used qmake but I'd like to experiment with cmake..
I would like to work with a project structure like the following:
Myproject
-- build
-- release
-- debug
-- src
-- mysource1.cpp
-- mysource1.h
-- mysource2.cpp
-- mysource2.h
...
-- main.cpp
myexecutable_release
myexecutable_debug
CMakeLists.txt
How do I set CMakeLists.txt to use the above structure ? How do I associate debug and release configuration using QtCreator ?
Or, as I don't have any particular complex need, should I just forget it and continue using qmake ? (it's a scientific software for linux/windows)
BDW: yes, I have read the CMake tutorial, but instead of starting from basic things like this question they already introduce complex topics like introspection and generators.. maybe different audience ??
project (Myproject)
set(sources src/mysource1.cpp
src/mysource2.cpp
src/mysource1.h
src/mysource2.h
src/main.cpp
)
add_executable(myexecutable ${sources})
In the folder build run
cmake ..
and build. For gcc debug builds, see this answer. For additional options (e.g. different generators) consult cmake documentation.
There is some CMake magic I don't understand. How should a CMakeLists.txt file look like for a small C++ project with directories like this:
.
├── bin
└── src
├── src
└── test
bin — directory for built program
src/src — directory for source
src/test — directory for tests
The tests will need to include files from src/src.
I'd like to manage all the operations from cmake, however at this moment I even can't cause cmake to compile file in src/c.cpp.
Any help, links are welcome.
Your CMake files should reside in the main source directory and its sub-directories. The easiest approach is to have one CMakeLists.txt in the src directory, which includes all files from src/src and src/test. A very minimalistic example could look like the following:
# CMakeLists.txt in src
project(myExample)
set(myExample_SOURCES
src/file1.cpp
src/main.cpp)
add_executable(myExecutable ${myExample_SOURCES})
set(myExample_test_SOURCES
src/file1.cpp
test/test_file2.cpp
test/test_main.cpp)
add_executable(myTestSuite ${myExample_test_SOURCES})
The output directory is normally not specified, because you can have different active
builds in parallel with
different options, e.g. you can have one build in debug mode -O0 -g, another one in release mode with -O2 -g flags and a third one in release mode with heavy optimization flags -O3. Every build resides in its own directory (e.g. build-debug, build-rel,
build-opt).
You should create the output directory (bin in your case) manually and call the cmake command inside this directory. As an argument you have to supply the path to the main CMakeLists.txt. In other words, just execute
cmake ../src
when you are inside bin. This will take all files from the src directory and put the output to the bin directory.
You can easily create a second output directory, say bin2, where you specify different build flags. The ccmake provides a very minimalistic GUI for that.
This helped me to start with cmake examples.html
How do I tell cmake where it should output its build data?
Let's say I have a dir with the source code called src/,
and then since cmake outputs a lot of files I would like him to put all of that in
a dir called build/.
BUT I would like him to put the generated Makefile in the project root,
so I don't have to go into the build dir to build the application.
Is this possible with cmake?
I have managed to get the cmake out put if I fun cmake in the build dir like this:
cd build/
cmake ../src/
make
./hello
But it would be nice to stay in the project root and type something like this
cmake
make
./hello
I guess that I need to put a CMakeList.txt in the project root with some magic commands telling him where he could put the object files and where he can find the source code.
Thanks
Update:
Since my question is a little bit vague.
After I have run the cmake commands this is how I would like my tree to look like:
src/CMakeLists.txt
src/hello.c
src/hello.h
build/CMakeCache.txt
build/CMakeFiles/
build/cmake_install.cmake
CMakeLists.txt
Makefile
So the question is how should the CMakeLists.txt look like in this setup.
CMakeLists.txt
src/CMakeLists.txt
But maybe that is not possible?
BUT I would like him to put the generated Makefile in the project root, so I don't have to go into the build
dir to build the application.
cmake not designed for that, as I know,
BUT you can stay in the project root and type:
make -C build
./hello
with custom build rules or set_target_properties,
you can force cmake to put result executable to
sources directory or you can use
./build/hello
Type "cd build && cmake .." you need only once,
after that make will automaticaly start cmake, if something
changed.
cmake wants you to have a fresh build directory.
Okay, i get what you want. I think, you can achieve this with some machinery in CMakeLists.txt. Of course, it's not option if you are not project developer.
In root CMakeLists.txt you can add file(WRITE ...) command, which would write Makefile into ${CMAKE_SOURCE_DIR}. This Makefile would contain these commands for every target:
<target>:
cd ${CMAKE_BUILD_DIR} && ${CMAKE_MAKE_PROGRAM} <target>
So, now you can run make from source dir and it will build your project in build dir.
Simply use
cmake .
make
in your src directory. The (.) dot on unix systems addresses the current directory. Keep in mind doing so is actually not recommended since there will be a lot of build files in your src directory you'll have to clean up afterwards or at release time.