Table of contents
Example
Source video: 【cmake教程】为你的项目引入外部第三方库(以真实项目partio为例) - 只喝白开水
Prepare: Download the code of partio.
|
|
-
Directory structure:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20(base) yi@yi:~/Downloads/partio$ tree -L 2 . ├── build_wheels.sh ├── CMakeLists.txt ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── setup.cfg ├── setup.py └── src ├── data ├── doc ├── lib ├── Makefile ├── py ├── tests └── tools 7 directories, 9 files
Four steps for testing the introduced library:
-
Copy codes
Only the codes
partio/src/lib/are needed in this example., so copy it to your own project, and place it under the directoryexample_cmake/external/partio/as shown below:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17(base) yi@yi:~/Downloads/example_cmake$ tree . ├── CMakeLists.txt ├── external │ └── partio │ ├── CMakeLists.txt # partio/src/lib/CMakeLists.txt │ ├── core │ ├── io │ ├── PartioAttribute.h │ ├── Partio.h │ ├── PartioIterator.h │ ├── PartioVec3.h │ └── test │ └── test_helloWorld.cpp └── src ├── CMakeLists.txt └── main.cpp -
Inherit (Copy) the original CMakeListst settings:
Copy all contents of the top-level CMakeLists.txt of the original partio project to the front of the copied lib’s
external/partio/CMakeLists.txt, i.e., the previouspartio/src/lib/CMakeLists.txt, as it’s included first.So as to retain some macro settings and variables for compiling. And then delete unnecessary settings.
-
The top-level
CMakeLists.txtof your own project is:1 2 3 4 5 6 7 8 9cmake_minimum_required(VERSION 3.20) project(learn-cmake LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # each sub-directory has its own CMakeLists.txt: add_subdirectory(external/partio) add_subdirectory(src)The
src/folder stores your own code, which will be built to an executable program. So, the executable in thesrc/CMakeLists.txtis your ownmain.cpp:1add_executable(main main.cpp)An example of
src/main.cpp:1 2 3int main(int argc, char const *argv[]){ return 0; } -
Write an testing executable program (
test_helloWorld.cpp) inside theexternal/partio.In this case,
test_helloWorld.cppcalls functions inexternal/partio“natively”. However, this isn’t the case for calling its functions from another project.1 2 3 4#include "Partio.h" int main(){ Partio::ParticlesDataMutable* data = Partio::read("bgeoFile"); std::cout << "Number of " << std::endl;}Set the
external/partio/CMakeLists.txtto compile it as an executable application:1 2 3 4add_library(partio ${PARTIO_LIBRARY_TYPE} ${io_cpp} ${core_cpp}) # Setting target_include_directories .... add_executable(test_helloWorld ${CMAKE_CURRENT_LIST_DIR}/test/test_helloWorld.cpp) target_link_libraries(test_helloWorld PRIVATE partio)After compiling, a binary file
test_helloWorldwill be generated under “external/partio”.This test code has nothing to do with the other subdirectories’ “src/”, where the
mainapplication will be build based on its own CMakeLists.txt.The CMakeLists.txt of different projects are independent to each other.
The most commonly used rule is “One CMakeLists.txt per target”. cmake: add_subdirectory() vs include() - SO
Test DiffRast
I want to debug the library diff-gaussian-rasterization.
-
I can create a project, and make the diffRast as an external library to call its methods.
1 2 3 4mkdir debug_diff_rast && cd debug_diff_rast git init mkdir external && cd external git submodule add https://github.com/graphdeco-inria/diff-gaussian-rasterizationDirectory structure:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29(base) yi@yi:~/Downloads/debug_diff_rast$ tree . ├── CMakeLists.txt ├── main.cpp ├── README.md └── external └── diff-gaussian-rasterization ├── CMakeLists.txt ├── cuda_rasterizer │ ├── auxiliary.h │ ├── backward.cu │ ├── backward.h │ ├── config.h │ ├── forward.cu │ ├── forward.h │ ├── rasterizer.h │ ├── rasterizer_impl.cu │ └── rasterizer_impl.h ├── diff_gaussian_rasterization │ └── __init__.py ├── ext.cpp ├── LICENSE.md ├── rasterize_points.cu ├── rasterize_points.h ├── README.md ├── setup.py └── third_party ├── glm └── stbi_image_write.h -
The original
diff-gaussian-rasterization/CMakeLists.txtwould build the project to a library (CudaRasterizer), not an executable application.The command
add_subdirectory()is used to add an external project, which will automatically build according to its ownCMakeLists.txtwhen the root CMakeLists.txt starts building.- If without
add_subdirectory, an error would occur:CMake Error at CMakeLists.txt:17 (target_include_directories): Cannot specify include directories for target which is not built by this project.
Hence, the library
CudaRasterizeris linked as a static library throughtarget_link_libraries()to an executable programMyAppbased on themain.cpp, and debug it.In summary, the top-level (root) CMakeLists.txt needs to link 2 libraries:
libtorchandCudaRasterizer, as follows.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17cmake_minimum_required(VERSION 3.20 FATAL_ERROR) project(MyApp) # ${PROJECT_NAME} find_package(Torch REQUIRED) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TORCH_CXX_FLAGS}") add_subdirectory(external/diff-gaussian-rasterization) add_executable(MyApp main.cpp) set_property(TARGET MyApp PROPERTY CXX_STANDARD 17) target_link_libraries(MyApp "${TORCH_LIBRARIES}") target_link_libraries(MyApp CudaRasterizer) # rasterization_points.cu and ~.h aren't in their CMakeLists.txt, so need: target_sources(MyApp PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/external/diff-gaussian-rasterization/rasterize_points.cu) target_include_directories(MyApp PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/external/diff-gaussian-rasterization)In the
diff-gaussian-rasterization/CMakeLists.txt, the header files inside the foldercuda_rasterizer/are included and set toPUBLIC, such that when the library is linked to the target, those headers will be appended to the target’sINCLUDE_DIRECTORIES. So they can be included via their filenames, for example#include "forward.h", without relative path. (Not sure. 2023-11-16)However, the
rasterize_point.hisn’t included into the library (CudaRasterizer), so it has to be included using its relative path.Specifically, in the
main.cpp:1 2#include <torch/torch.h> #include "external/diff-gaussian-rasterization/rasterize_points.h"With adding that header file (declaration) to executable target, the compilation of
main.cppcan pass. However, if the function bodyrasterize_points.cu(function implementation) isn’t added to the executable in CMakeLists.txt, there will be a linking error:1 2/usr/bin/ld: CMakeFiles/MyApp.dir/main.cpp.o: in function `main': main.cpp:(.text.startup+0x383): undefined reference to `RasterizeGaussiansCUDA(at::Tensor const&, ...)' - If without
-
Two modifications for source code of
diff-gaussian-rasterization:-
rasterize_point.cuisn’t included into theCudaRasterizerlibrary, because it’s not specified within theadd_library()function in thediff-gaussian-rasterization/CMakeLists.txt.Therefore, when the project
diff-gaussian-rasterizationis built by executingcmake -B ./build, the .cu filerasterize_point.cuisn’t compiled.Thus, the following error of missing
Python.hwon’t be tiggered. -
rasterize_point.cuincludes header<torch/extension.h>, which is used for interacting with Python. Based on that, the libraryCudaRasterizercan be called in Python scripts as a PyTorch extension.Therefore, the Python development headers must be present to compile it. Otherwise, an error would occur:
1 2 3 4 5 6 7 8 9In file included from /usr/local/libtorch/include/torch/csrc/Device.h:3, from /usr/local/libtorch/include/torch/csrc/api/include/torch/python.h:8, from /usr/local/libtorch/include/torch/extension.h:6, from /home/yi/Downloads/diff-gaussian-rasterization/rasterize_points.h:13, from /home/yi/Downloads//diff-gaussian-rasterization/test_DiffRast.cpp:2: /usr/local/libtorch/include/torch/csrc/python_headers.h:10:10: fatal error: Python.h: No such file or directory 10 | #include <Python.h> | ^~-~~-~~-~~-~~ compilation terminated.Previously, my trivial experiments only used LibTorch tensors without interacting with python. Therefore, no error was reported when building without specifying the path of Python.
But the Python development headers is already installed:
1 2sudo apt-get install python3-dev apt list python3-devA possible solution is to include python in CMakeLists.txt: Similar issure
-
Since here I just want to debug it as a C++ project, instead of for python, and I have LibTorch installed.
So I changed
#include <torch/extension.h>to#include <torch/torch.h>in the 2 files: “rasterize_points.cu” and “rasterize_points.h”.
-
-
Build the top-level project “debug_diff_rast”:
1 2 3 4 5 6cd ~/Downloads/debug_diff_rast # configure: cmake -B ./build -DCMAKE_PREFIX_PATH=/usr/local/libtorch -GNinja # build: cmake --build ./build ./build/MyApp
Ref:
【公开课】现代CMake高级教程(持续更新中)- 双笙子佯谬 - bilibili
Include Python
cmake
(2024-01-29)
The direct solution for Python.h: No such file or directory could be include Python in the CMakeLists.txt,
-
This is inspired by Example debugging mixed Python C++ in VS Code - Nadiah Pardede Kristensen, where
#include <Python.h>will be reported the error by Intellisense, if without specifying “includePath” for Python in the.vscode/c_cpp_properties.json. -
CMake built-in module: FindPython3 mentioned in How do I get cmake to find python3.9 instead of python3.10 on ubuntu22.04
g++ CLI
(2024-01-31)
- Check if the Python Development Libraries has been installed:
dpkg -l | grep python3-dev. devicetests
-
Install it:
sudo apt-get install python3-dev -
Find where it is:
find / -type f -iname 'python.h' 2>/dev/nullDebian / Ubuntu: Fatal error: Python.h: No such file or Directory -
The directory of Python is also required to be included:
g++ -I/usr/include/python3.8 main.cpp. GeeksforGeeksA complete example command is:
1 2 3 4 5 6 7 8 9 10 11 12(AIkui) yi@yi-Alien:~/Downloads/CppCudaExt_PT_Tut_AIkui$ g++ \ -g -std=c++17 \ -I/usr/local/libtorch/include \ -I/usr/local/libtorch/include/torch/csrc/api/include \ -I/usr/local/libtorch/include/torch \ -I/home/yi/anaconda3/envs/AIkui/include/python3.10 \ -I./include \ # Custom functions declarations -L/usr/local/libtorch/lib \ -Wl,-rpath,/usr/local/libtorch/lib \ test_None_tensor.cpp \ # main function definition interpolation.cpp \ # Custom functions definitions -ltorch -ltorch_cpu -lc10
-
A demo
Refer to Nathan Sebhastian
1 2 3 4 5 6 7 8#include<Python.h> #include<stdio.h> int main() { printf("Hello World!\n"); return 0; }Compile:
g++ test_python.cpp, an error occurs:1 2 3 4 5(base) yi@yi-Alienware-Aurora-R8:~/Downloads/Cpp_Study$ g++ test_python.cpp test_python.cpp:1:9: fatal error: Python.h: No such file or directory 1 | #include<Python.h> | ^~~~~~~~~~ compilation terminated.Locate header file:
1 2 3sudo apt install mlocate sudo updatedb locate Python.hInclude Python dir:
gcc test_python.cpp -I/usr/include/python3.8