I try to use cmake in my project (actually move from make to cmake). I bump into a problem that I can't solve. I try to streamline my architecture like this (hope this is not too streamlined). I use ld -r here as an example custom command that produce files and intermediate files.
Here is my file structure.
.
`-- libs
|-- CMakeLists.txt
|-- l1
| |-- CMakeLists.txt
| |-- l1_f1.c
| `-- l1_f2.c
`-- l2
|-- CMakeLists.txt
|-- l2_f1.c
`-- l2_f2.c
The .c files
./libs/l1/l1_f1.c::
#include <stdio.h>
int v1;
int l1_f1(){ printf("In l1_f1()\n");}
./libs/l1/l1_f2.c::
#include <stdio.h>
int l1_f2(){ printf("In l1_f2()\n");}
./libs/l2/l2_f1.c::
#include <stdio.h>
int l2_f1(){ printf("In l2_f1()\n");}
./libs/l2/l2_f2.c::
#include <stdio.h>
int l2_f2(){ printf("In l2_f2()\n");}
And my CMakeLists.txt files
./libs/CMakeLists.txt::
cmake_minimum_required(VERSION 3.10)
project(PL VERSION 1.0)
add_subdirectory(../libs/l1 libs/l1)
add_subdirectory(../libs/l2 libs/l2)
add_custom_command(
OUTPUT l.a
COMMAND ld -r libs/l1/l1.o libs/l2/l2.o -o l.o
COMMAND rm -f l.a
COMMAND ar r l.a l.o
COMMAND rm -f l.o
DEPENDS L1 L2
)
add_custom_target(
LA
ALL
DEPENDS l.a
)
./libs/l1/CMakeLists.txt::
add_library(l1 OBJECT l1_f1.c l1_f2.c)
add_custom_command(
OUTPUT l1.o
COMMAND ld -r $<TARGET_OBJECTS:l1> -o l1.o
DEPENDS $<TARGET_OBJECTS:l1>
COMMAND_EXPAND_LISTS
)
add_custom_target(
L1
ALL
DEPENDS l1.o
)
./libs/l2/CMakeLists.txt::
add_library(l2 OBJECT l2_f1.c l2_f2.c)
add_custom_command(
OUTPUT l2.o
COMMAND ld -r $<TARGET_OBJECTS:l2> -o l2.o
DEPENDS $<TARGET_OBJECTS:l2>
COMMAND_EXPAND_LISTS
)
add_custom_target(
L2
ALL
DEPENDS l2.o
)
Now the question
I run the original cmake like this
mkdir build && cd build && cmake -G Ninja ../libs && ninja
-- The C compiler identification is GNU 7.4.0
-- The CXX compiler identification is GNU 7.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/g++
-- Check for working CXX compiler: /usr/bin/g++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/phi/p2/build
[7/7] Generating l.a
ar: creating l.a
I am happy with that l.a is created and doing a nm(1) on it shows the v1 global variable.
nm l.a
l.o:
U _GLOBAL_OFFSET_TABLE_
0000000000000000 T l1_f1
0000000000000013 T l1_f2
0000000000000026 T l2_f1
0000000000000039 T l2_f2
U puts
0000000000000004 C v1
Now the problem, I touch 1 file l1_f1.c and rebuild
VY$ sed -i 's/v1/v2/' ../libs/l1/l1_f1.c
VY$ ninja
[2/2] Generating l1.o
As we see here l.a is not rebuild, despite I thought I made a dep for regen it. Obvioulsy I must be wrong, I am new to cmake.
The nm(1) confirm l.a is not regened.
VY$ nm l.a libs/l1/l1.o
l.a:
l.o:
U _GLOBAL_OFFSET_TABLE_
0000000000000000 T l1_f1
0000000000000013 T l1_f2
0000000000000026 T l2_f1
0000000000000039 T l2_f2
U puts
0000000000000004 C v1
libs/l1/l1.o:
U _GLOBAL_OFFSET_TABLE_
0000000000000000 T l1_f1
0000000000000013 T l1_f2
U puts
0000000000000004 C v2
Can someone enlight me how I could get l.a regened ?
Thanx in advance, cheers.
The following is added after Tsyvarev answer proposition.
1) Adding file-level dependencies in main CMakeLists.txt prevent initial build. Note that your initial line DEPENDS libs/l1/l1.o libs/l1/l2.o generate an error as it look file in the source tree instead of the build tree so I changed it to DEPENDS ../build/libs/l1/l1.o ../build/libs/l2/l2.o
cmake_minimum_required(VERSION 3.10)
project(PL VERSION 1.0)
add_subdirectory(../libs/l1 libs/l1)
add_subdirectory(../libs/l2 libs/l2)
add_custom_command(
OUTPUT l.a
COMMAND ld -r libs/l1/l1.o libs/l2/l2.o -o l.o
COMMAND rm -f l.a
COMMAND ar r l.a l.o
COMMAND rm -f l.o
DEPENDS ../build/libs/l1/l1.o ../build/libs/l2/l2.o
DEPENDS L1 L2
)
add_custom_target(
LA
ALL
DEPENDS l.a
)
This give the following output on initial build
VY$ cd .. && rm -rf build && mkdir build && cd build && cmake -G Ninja ../libs && ninja
-- The C compiler identification is GNU 7.4.0
-- The CXX compiler identification is GNU 7.4.0
... [removed output]
-- Configuring done
-- Generating done
-- Build files have been written to: /home/phi/p2/build
ninja: error: '/home/phi/p2/build/libs/l1/l1.o', needed by 'l.a', missing and no known rule to make it
2) rebuilding the project without the file-level dep.
VY$ cd .. && rm -rf build && mkdir build && cd build && cmake -G Ninja ../libs && ninja
-- The C compiler identification is GNU 7.4.0
-- The CXX compiler identification is GNU 7.4.0
... [removed output]
-- Configuring done
-- Generating done
-- Build files have been written to: /home/phi/p2/build
[7/7] Generating l.a
ar: creating l.a
3) With this initial build and your file-dep added again in the CMakethen ask for a partial rebuild give this
Initial setup after project build.
VY$ ninja;nm libs/l1/CMakeFiles/l1.dir/l1_f1.c.o ; nm l.a
ninja: no work to do.
U _GLOBAL_OFFSET_TABLE_
0000000000000000 T l1_f1
U puts
0000000000000004 C v1
l.o:
U _GLOBAL_OFFSET_TABLE_
0000000000000000 T l1_f1
0000000000000013 T l1_f2
0000000000000026 T l2_f1
0000000000000039 T l2_f2
U puts
0000000000000004 C v1
So this is v1, touching 1 file to make v2 and rebuild with your file-level dep
cmake_minimum_required(VERSION 3.10)
project(PL VERSION 1.0)
add_subdirectory(../libs/l1 libs/l1)
add_subdirectory(../libs/l2 libs/l2)
add_custom_command(
OUTPUT l.a
COMMAND ld -r libs/l1/l1.o libs/l2/l2.o -o l.o
COMMAND rm -f l.a
COMMAND ar r l.a l.o
COMMAND rm -f l.o
DEPENDS ../build/libs/l1/l1.o ../build/libs/l2/l2.o
DEPENDS L1 L2
)
add_custom_target(
LA
ALL
DEPENDS l.a
)
give this
VY$ ninja
[0/1] Re-running CMake...
-- Configuring done
-- Generating done
-- Build files have been written to: /home/phi/p2/build
[2/2] Generating l1.o
VY$ nm libs/l1/CMakeFiles/l1.dir/l1_f1.c.o ; nm l.a
U _GLOBAL_OFFSET_TABLE_
0000000000000000 T l1_f1
U puts
0000000000000004 C v2
l.o:
U _GLOBAL_OFFSET_TABLE_
0000000000000000 T l1_f1
0000000000000013 T l1_f2
0000000000000026 T l2_f1
0000000000000039 T l2_f2
U puts
0000000000000004 C v1
VY$ ninja
[1/1] Generating l.a
ar: creating l.a
VY$ nm libs/l1/CMakeFiles/l1.dir/l1_f1.c.o ; nm l.a
U _GLOBAL_OFFSET_TABLE_
0000000000000000 T l1_f1
U puts
0000000000000004 C v2
l.o:
U _GLOBAL_OFFSET_TABLE_
0000000000000000 T l1_f1
0000000000000013 T l1_f2
0000000000000026 T l2_f1
0000000000000039 T l2_f2
U puts
0000000000000004 C v2
As we see here, on first ninja we got a cmake rebuild because I added back the file-level dep. Then only the l1.o is rebuild not l.o then l.a.
Second ninja trig the l.a rebuild.
It sounds like make basic dependencies actiopn rule is pretty magic with cmake, hope someone could help me here.
Cheers.
The following is added after Tsyvarev latest comment.
The final fix from Tsyvarev make it working, need the set_source_files_propoerties()
The top CMakeLists.txt now look like this
cmake_minimum_required(VERSION 3.10)
project(PL VERSION 1.0)
add_subdirectory(../libs/l1 libs/l1)
add_subdirectory(../libs/l2 libs/l2)
add_custom_command(
OUTPUT l.a
COMMAND ld -r ${CMAKE_CURRENT_BINARY_DIR}/libs/l1/l1.o
${CMAKE_CURRENT_BINARY_DIR}/libs/l2/l2.o -o l.o
COMMAND rm -f l.a
COMMAND ar r l.a l.o
COMMAND rm -f l.o
DEPENDS # Use absolute paths for files for prevent confusion
${CMAKE_CURRENT_BINARY_DIR}/libs/l1/l1.o
${CMAKE_CURRENT_BINARY_DIR}/libs/l2/l2.o
# Target-level dependencies are needed too
L1 L2
)
set_source_files_properties(
${CMAKE_CURRENT_BINARY_DIR}/libs/l1/l1.o
${CMAKE_CURRENT_BINARY_DIR}/libs/l2/l2.o
PROPERTIES GENERATED TRUE
)
add_custom_target(
LA
ALL
DEPENDS l.a
)
And the builds, full and partial, gives the correct answer.
VY$ cd .. && rm -rf build && mkdir build && cd build && cmake -G Ninja ../libs && ninja
-- The C compiler identification is GNU 7.4.0
-- The CXX compiler identification is GNU 7.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/g++
-- Check for working CXX compiler: /usr/bin/g++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/phi/p2/build
[7/7] Generating l.a
ar: creating l.a
VY$ ninja;nm libs/l1/CMakeFiles/l1.dir/l1_f1.c.o ; nm l.a
ninja: no work to do.
U _GLOBAL_OFFSET_TABLE_
0000000000000000 T l1_f1
U puts
0000000000000004 C v1
l.o:
U _GLOBAL_OFFSET_TABLE_
0000000000000000 T l1_f1
0000000000000013 T l1_f2
0000000000000026 T l2_f1
0000000000000039 T l2_f2
U puts
0000000000000004 C v1
VY$ sed -i 's/v1/v2/' ../libs/l1/l1_f1.c
VY$ ninja;nm libs/l1/CMakeFiles/l1.dir/l1_f1.c.o ; nm l.a
[3/3] Generating l.a
ar: creating l.a
U _GLOBAL_OFFSET_TABLE_
0000000000000000 T l1_f1
U puts
0000000000000004 C v2
l.o:
U _GLOBAL_OFFSET_TABLE_
0000000000000000 T l1_f1
0000000000000013 T l1_f2
0000000000000026 T l2_f1
0000000000000039 T l2_f2
U puts
0000000000000004 C v2
As we see here l.a is not rebuild, despite I thought I made a dep for regen it.
You don't actually make l.a dependent from l1.o and other object files.
The line
DEPENDS L1 L2
in the custom command which creates l.a means only dependencies between the target LA (the target which depends from l.a) and the targets L1 and L2. This is described in the documentation for the add_custom_command. But your custom command itself doesn't have a dependency from l1.o file which you need.
The dependency between the targets forces only LA target to be built after L1 and L2.
Correct way is to specify for add_custom_command file-level dependencies.
But, as dependency files are created in other CMakeLists.txt, additional steps are required:
Target-level dependencies. It involves targets which produces dependency files.
Marking the dependency files as GENERATED. Otherwise CMake would treat these files as already existed on configuration stage.
In result:
add_custom_command(
OUTPUT l.a
COMMAND ld -r libs/l1/l1.o libs/l2/l2.o -o l.o
COMMAND rm -f l.a
COMMAND ar r l.a l.o
COMMAND rm -f l.o
DEPENDS
# Use absolute paths for files for prevent confusion
${CMAKE_CURRENT_BINARY_DIR}/libs/l1/l1.o
${CMAKE_CURRENT_BINARY_DIR}/libs/l2/l2.o
# Target-level dependencies are needed too
L1 L2
)
set_source_files_properties(
${CMAKE_CURRENT_BINARY_DIR}/libs/l1/l1.o
${CMAKE_CURRENT_BINARY_DIR}/libs/l2/l2.o
PROPERTIES GENERATED TRUE
)
The rationale behind needs to specify file-level dependencies even if you have target-level ones is that generally CMake has no notion about OUTPUT file for the target. Such notion exists only for targets create by add_executable or add_library, and in this case DEPENDS from such target actually enriches custom command with both target-level and file-level dependencies.
Related
TL;DR: Why moving stuff around from the CMakeLists.txt to a dedicated toolchain file plays a role for find_package?
Trying to cross-compile with cmake and compile/link against pthread, I have the following dummy source file and CMakeLists.txt which work as expected together:
main.cc
#include <iostream>
#include <bits/c++config.h> // needed in the real world
int main()
{
std::cout << "Hello World !\n";
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.0.0)
project(test VERSION 0.0.1)
set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_COMPILER clang)
set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_CXX_COMPILER_TARGET arm-linux-gnueabihf)
add_compile_options(-mtune=cortex-a9)
add_compile_definitions(_ARM_GCC_)
# Looking for cross compiler includes; maybe looking for rootfs-like stuff would be better
file(GLOB cross_includes LIST_DIRECTORIES true "/usr/arm-linux-gnueabihf/include/c++/*/arm-linux-gnueabihf/")
include_directories(SYSTEM ${cross_includes})
include_directories(SYSTEM /usr/arm-linux-gnueabihf/include)
find_package(Threads REQUIRED) # Not strictly necessary in this example but needed in the real world
add_executable(test main.cc)
Test:
$> rm -rf build/ && cmake -B build/ && make VERBOSE=1 -C build/
-- The C compiler identification is Clang 11.0.1
-- The CXX compiler identification is Clang 11.0.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/clang - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/clang++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed
-- Looking for pthread_create in pthreads
-- Looking for pthread_create in pthreads - not found
-- Looking for pthread_create in pthread
-- Looking for pthread_create in pthread - found
-- Found Threads: TRUE
-- Configuring done
-- Generating done
-- Build files have been written to: /home/jp/sandbox/so/cmake/build
make: Entering directory '/home/jp/sandbox/so/cmake/build'
/usr/bin/cmake -S/home/jp/sandbox/so/cmake -B/home/jp/sandbox/so/cmake/build --check-build-system CMakeFiles/Makefile.cmake 0
/usr/bin/cmake -E cmake_progress_start /home/jp/sandbox/so/cmake/build/CMakeFiles /home/jp/sandbox/so/cmake/build//CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: Entering directory '/home/jp/sandbox/so/cmake/build'
make -f CMakeFiles/test.dir/build.make CMakeFiles/test.dir/depend
make[2]: Entering directory '/home/jp/sandbox/so/cmake/build'
cd /home/jp/sandbox/so/cmake/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /home/jp/sandbox/so/cmake /home/jp/sandbox/so/cmake /home/jp/sandbox/so/cmake/build /home/jp/sandbox/so/cmake/build /home/jp/sandbox/so/cmake/build/CMakeFiles/test.dir/DependInfo.cmake --color=
Dependee "/home/jp/sandbox/so/cmake/build/CMakeFiles/test.dir/DependInfo.cmake" is newer than depender "/home/jp/sandbox/so/cmake/build/CMakeFiles/test.dir/depend.internal".
Dependee "/home/jp/sandbox/so/cmake/build/CMakeFiles/CMakeDirectoryInformation.cmake" is newer than depender "/home/jp/sandbox/so/cmake/build/CMakeFiles/test.dir/depend.internal".
Scanning dependencies of target test
make[2]: Leaving directory '/home/jp/sandbox/so/cmake/build'
make -f CMakeFiles/test.dir/build.make CMakeFiles/test.dir/build
make[2]: Entering directory '/home/jp/sandbox/so/cmake/build'
[ 50%] Building CXX object CMakeFiles/test.dir/main.cc.o
/usr/bin/clang++ --target=arm-linux-gnueabihf -D_ARM_GCC_ -isystem /usr/arm-linux-gnueabihf/include/c++/10/arm-linux-gnueabihf -isystem /usr/arm-linux-gnueabihf/include -g -mtune=cortex-a9 -std=c++17 -o CMakeFiles/test.dir/main.cc.o -c /home/jp/sandbox/so/cmake/main.cc
[100%] Linking CXX executable test
/usr/bin/cmake -E cmake_link_script CMakeFiles/test.dir/link.txt --verbose=1
/usr/bin/clang++ --target=arm-linux-gnueabihf -g -rdynamic CMakeFiles/test.dir/main.cc.o -o test
make[2]: Leaving directory '/home/jp/sandbox/so/cmake/build'
[100%] Built target test
make[1]: Leaving directory '/home/jp/sandbox/so/cmake/build'
/usr/bin/cmake -E cmake_progress_start /home/jp/sandbox/so/cmake/build/CMakeFiles 0
make: Leaving directory '/home/jp/sandbox/so/cmake/build'
So far, everything works fine.
Now, the tricky part: I'd like to put the cross-compilation specific stuff in a toolchain.cmake file
toolchain.cmake
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_COMPILER clang)
set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_CXX_COMPILER_TARGET arm-linux-gnueabihf)
add_compile_options(-mtune=cortex-a9)
add_compile_definitions(_ARM_GCC_)
# Looking for cross compiler includes; maybe looking for rootfs-like stuff would be better
file(GLOB cross_includes LIST_DIRECTORIES true "/usr/arm-linux-gnueabihf/include/c++/*/arm-linux-gnueabihf/")
include_directories(SYSTEM ${cross_includes})
include_directories(SYSTEM /usr/arm-linux-gnueabihf/include)
new CMakeLists.txt
cmake_minimum_required(VERSION 3.0.0)
project(test VERSION 0.0.1)
set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
find_package(Threads REQUIRED) # Not strictly necessary in this example but needed in the real world
add_executable(test main.cc)
Test:
$> rm -rf build/ && cmake -B build/ -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake && make VERBOSE=1 -C build/
-- The C compiler identification is Clang 11.0.1
-- The CXX compiler identification is Clang 11.0.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/clang - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/clang++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Looking for pthread.h
-- Looking for pthread.h - not found
CMake Error at /usr/share/cmake-3.18/Modules/FindPackageHandleStandardArgs.cmake:165 (message):
Could NOT find Threads (missing: Threads_FOUND)
Call Stack (most recent call first):
/usr/share/cmake-3.18/Modules/FindPackageHandleStandardArgs.cmake:458 (_FPHSA_FAILURE_MESSAGE)
/usr/share/cmake-3.18/Modules/FindThreads.cmake:234 (FIND_PACKAGE_HANDLE_STANDARD_ARGS)
CMakeLists.txt:11 (find_package)
-- Configuring incomplete, errors occurred!
See also "/home/jp/sandbox/so/cmake/build/CMakeFiles/CMakeOutput.log".
See also "/home/jp/sandbox/so/cmake/build/CMakeFiles/CMakeError.log".
Actually, cmake finds pthread.h but clang cannot compile it (wrong floating point abi used; stubs-hard.h should be included)
build/CMakeFiles/CMakeError.log
Determining if the include file pthread.h exists failed with the following output:
Change Dir: /home/jp/sandbox/so/cmake/build/CMakeFiles/CMakeTmp
Run Build Command(s):/usr/bin/gmake cmTC_76e89/fast && /usr/bin/gmake -f CMakeFiles/cmTC_76e89.dir/build.make CMakeFiles/cmTC_76e89.dir/build
gmake[1]: Entering directory '/home/jp/sandbox/so/cmake/build/CMakeFiles/CMakeTmp'
Building C object CMakeFiles/cmTC_76e89.dir/CheckIncludeFile.c.o
/usr/bin/clang -D_ARM_GCC_ -isystem /usr/arm-linux-gnueabihf/include/c++/10/arm-linux-gnueabihf -isystem /usr/arm-linux-gnueabihf/include/gnu -isystem /usr/arm-linux-gnueabihf/include -mtune=cortex-a9 -o CMakeFiles/cmTC_76e89.dir/CheckIncludeFile.c.o -c /home/jp/sandbox/so/cmake/build/CMakeFiles/CMakeTmp/CheckIncludeFile.c
In file included from /home/jp/sandbox/so/cmake/build/CMakeFiles/CMakeTmp/CheckIncludeFile.c:1:
In file included from /usr/arm-linux-gnueabihf/include/pthread.h:21:
In file included from /usr/arm-linux-gnueabihf/include/features.h:485:
/usr/arm-linux-gnueabihf/include/gnu/stubs.h:7:11: fatal error: 'gnu/stubs-soft.h' file not found
# include <gnu/stubs-soft.h>
^~~~~~~~~~~~~~~~~~
1 error generated.
gmake[1]: *** [CMakeFiles/cmTC_76e89.dir/build.make:85: CMakeFiles/cmTC_76e89.dir/CheckIncludeFile.c.o] Error 1
gmake[1]: Leaving directory '/home/jp/sandbox/so/cmake/build/CMakeFiles/CMakeTmp'
gmake: *** [Makefile:140: cmTC_76e89/fast] Error 2
Some more Info:
I made sure the toolchain.cmake is considered (triggered a parse error to check)
$> cat toolchain.cmake CMakeLists.txt
produces the same output as the "original" CMakeLists.txt
pthread.h can be found on my System at the following locations:
$> find /usr/ -name pthread.h
/usr/arm-linux-gnueabi/include/pthread.h
/usr/arm-linux-gnueabihf/include/pthread.h
/usr/include/newlib/pthread.h /usr/include/pthread.h
As #Tsyvarev pointed out, the CMakeError.log contained useful information (the question was edited with its content).
The issue:
cmake finds pthread.h but clang cannot compile it
...
/usr/arm-linux-gnueabihf/include/gnu/stubs.h:7:11: fatal error: 'gnu/stubs-soft.h' file not found
...
The clang invocation is interesting because of "/usr/bin/clang" (expected clang++) and no -target flag used
The solution:
Tell cmake to also use a specific -target flag for C cross-compilers supoorting it:
Add the following in target.cmake
set(CMAKE_C_COMPILER_TARGET arm-linux-gnueabihf)
(Same target as CMAKE_CXX_COMPILER_TARGET)
Let's say I have a library A and a project B which uses A.
project(libA)
function(calledWhenLink target)
message(STATUS Hi ${target}) # Should print "Hi exeB"
endfunction()
add_library(libA INTERFACE)
project(exeB)
find_package(A REQUIRED)
target_link_library(exeB libA)
Is it possible to automatically call calledWhenLink() when the executable links to the library ?
Reasoning: As said in a comment, the original problem is that VTK needs to call CMake vtk_module_autoinit. My library uses VTK, and it seems better for all the samples to automatically call this when linked to the lib instead of copy paste the code in each CMakeLists. The problem is that vtk_module_autoinit is not working when called with the lib target instead ot the exe in my tests.
Yes, it is possible to run arbitrary CMake code at build time. However, it is not at all clear what you're really trying to do, so this might not be a good approach.
Here's a minimal example:
cmake_minimum_required(VERSION 3.21)
project(example)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/post-link.cmake" [[
message(STATUS "Hi ${target}")
]])
add_executable(exeB main.cpp)
add_custom_command(
TARGET exeB POST_BUILD
COMMAND "${CMAKE_COMMAND}"
-Dtarget=exeB
-P "${CMAKE_CURRENT_BINARY_DIR}/post-link.cmake"
)
Test interaction:
alex#alex-ubuntu:~/test$ cmake -G Ninja -S . -B build
-- The C compiler identification is GNU 9.3.0
-- The CXX compiler identification is GNU 9.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/alex/test/build
alex#alex-ubuntu:~/test$ cmake --build build/ --verbose
[1/2] /usr/bin/c++ -MD -MT CMakeFiles/exeB.dir/main.cpp.o -MF CMakeFiles/exeB.dir/main.cpp.o.d -o CMakeFiles/exeB.dir/main.cpp.o -c /home/alex/test/main.cpp
[2/2] : && /usr/bin/c++ CMakeFiles/exeB.dir/main.cpp.o -o exeB && cd /home/alex/test/build && /usr/bin/cmake -Dtarget=exeB -P /home/alex/test/build/post-link.cmake
-- Hi exeB
I am new to Docker container and kubenetes cluster. I am trying to run following section of command using buildah
##install cmake
USER root
RUN apt-get update && apt-get -y install cmake
USER ${user}
WORKDIR $HOME
## bustools_dev
RUN git clone https://github.com/Yenaled/bustools.git && \
cd bustools && \
mkdir build && \
cd build
RUN cmake ../
RUN make
RUN cd src
RUN mv bustools bustools_dev
RUN ENV PATH=$HOME/bustools/build/src/:${PATH}
but get the following error. What am I missing here?
STEP 17: WORKDIR $HOME
WARN[0002] SHELL is not supported for OCI image format, [/bin/bash -o pipefail -c] will be ignored. Must use `docker` format
--> 770a1b90326
STEP 18: RUN git clone https://github.com/Yenaled/bustools.git && cd bustools && mkdir build && cd build
Cloning into 'bustools'...
WARN[0005] SHELL is not supported for OCI image format, [/bin/bash -o pipefail -c] will be ignored. Must use `docker` format
--> 2b87555e927
STEP 19: RUN cmake ../
CMake Error: The source directory "/home" does not appear to contain CMakeLists.txt.
Specify --help for usage, or press the help button on the CMake GUI.
error building at STEP "RUN cmake ../": error while running runtime: exit status 1
ERRO[0111] exit status 1
I'd simplify the Dockerfile to avoid the issues with the WORKDIR setup that I think are the cause of the problem:
FROM debian:11
RUN apt-get update \
&& apt-get install --assume-yes --no-install-recommends --quiet \
ca-certificates \
cmake \
git \
g++ \
make \
libzip-dev \
&& apt-get clean all
WORKDIR /usr/local/src
RUN git clone https://github.com/Yenaled/bustools.git
RUN mkdir -p /usr/local/src/bustools/build
RUN cd /usr/local/src/bustools/build \
&& cmake .. \
&& make
[...]
Output
[...]
STEP 3/6: WORKDIR /usr/local/src
--> ffb056fd5b3
STEP 4/6: RUN git clone https://github.com/Yenaled/bustools.git
Cloning into 'bustools'...
--> 83afa44c5c8
STEP 5/6: RUN mkdir -p /usr/local/src/bustools/build
--> 2e6ed328088
STEP 6/6: RUN cd /usr/local/src/bustools/build && cmake .. && make
-- The C compiler identification is GNU 10.2.1
-- The CXX compiler identification is GNU 10.2.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
release mode
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed
-- Looking for pthread_create in pthreads
-- Looking for pthread_create in pthreads - not found
-- Looking for pthread_create in pthread
-- Looking for pthread_create in pthread - found
-- Found Threads: TRUE
-- Found ZLIB: /usr/lib/x86_64-linux-gnu/libz.so (found version "1.2.11")
-- Configuring done
-- Generating done
-- Build files have been written to: /usr/local/src/bustools/build
Scanning dependencies of target bustools_core
[ 4%] Building CXX object src/CMakeFiles/bustools_core.dir/BUSData.cpp.o
[ 8%] Building CXX object src/CMakeFiles/bustools_core.dir/Common.cpp.o
[ 13%] Building CXX object src/CMakeFiles/bustools_core.dir/bustools_capture.cpp.o
[ 17%] Building CXX object src/CMakeFiles/bustools_core.dir/bustools_clusterhist.cpp.o
[ 21%] Building CXX object src/CMakeFiles/bustools_core.dir/bustools_collapse.cpp.o
[ 26%] Building CXX object src/CMakeFiles/bustools_core.dir/bustools_correct.cpp.o
[ 30%] Building CXX object src/CMakeFiles/bustools_core.dir/bustools_count.cpp.o
[ 34%] Building CXX object src/CMakeFiles/bustools_core.dir/bustools_extract.cpp.o
[ 39%] Building CXX object src/CMakeFiles/bustools_core.dir/bustools_inspect.cpp.o
[ 43%] Building CXX object src/CMakeFiles/bustools_core.dir/bustools_linker.cpp.o
[ 47%] Building CXX object src/CMakeFiles/bustools_core.dir/bustools_main.cpp.o
[ 52%] Building CXX object src/CMakeFiles/bustools_core.dir/bustools_mash.cpp.o
[ 56%] Building CXX object src/CMakeFiles/bustools_core.dir/bustools_merge.cpp.o
[ 60%] Building CXX object src/CMakeFiles/bustools_core.dir/bustools_predict.cpp.o
[ 65%] Building CXX object src/CMakeFiles/bustools_core.dir/bustools_project.cpp.o
[ 69%] Building CXX object src/CMakeFiles/bustools_core.dir/bustools_sort.cpp.o
[ 73%] Building CXX object src/CMakeFiles/bustools_core.dir/bustools_text.cpp.o
[ 78%] Building CXX object src/CMakeFiles/bustools_core.dir/bustools_umicorrect.cpp.o
[ 82%] Building CXX object src/CMakeFiles/bustools_core.dir/bustools_whitelist.cpp.o
[ 86%] Building C object src/CMakeFiles/bustools_core.dir/roaring.c.o
[ 91%] Linking CXX static library libbustools_core.a
[ 91%] Built target bustools_core
Scanning dependencies of target bustools
[ 95%] Building CXX object src/CMakeFiles/bustools.dir/bustools_main.cpp.o
[100%] Linking CXX executable bustools
[100%] Built target bustools
--> b08bc457b5f
I created a cross compiler for the jetson nano using the following bash script:
#!/bin/bash
set -e
# mkdir cross-scratchpad
# cd cross-scratchpad
# FILES="http://ftpmirror.gnu.org/binutils/binutils-2.36.tar.gz
# http://ftpmirror.gnu.org/gcc/gcc-11.1.0/gcc-11.1.0.tar.gz &
# http://ftpmirror.gnu.org/glibc/glibc-2.33.tar.xz &
# http://ftpmirror.gnu.org/mpfr/mpfr-4.1.0.tar.xz
# http://ftpmirror.gnu.org/gmp/gmp-6.2.1.tar.xz &
# http://ftpmirror.gnu.org/mpc/mpc-1.2.1.tar.gz &
# ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-0.18.0.tar.bz2
# ftp://gcc.gnu.org/pub/gcc/infrastructure/cloog-0.18.1.tar.gz
# https://developer.nvidia.com/embedded/l4t/r32_release_v5.2/sources/t210/public_sources.tbz2"
# echo "$FILES" | xargs -n 1 -P 5 wget
# wait
for f in *.tar*; do tar xf "$f"; done
cd gcc-11.1.0
ln -s ../mpfr-4.1.0 mpfr
ln -s ../gmp-6.2.1 gmp
ln -s ../mpc-1.2.1 mpc
ln -s ../isl-0.18 isl
ln -s ../cloog-0.18.1 cloog
cd ..
sudo rm -rf /opt/cross/*
export PATH=/opt/cross/bin:"$PATH"
mkdir build-binutils
cd build-binutils
../binutils-2.36/configure --prefix=/opt/cross --target=aarch64-linux --disable-multilib --disable-werror
make -j8
make install
cd ..
tar -xjf public_sources.tbz2
cd Linux_for_Tegra/source/public/
tar -xjf kernel_src.tbz2
cd kernel/kernel-4.9
make ARCH=arm64 INSTALL_HDR_PATH=/opt/cross/aarch64-linux headers_install
cd ../../../../..
mkdir -p build-gcc
cd build-gcc
../gcc-11.1.0/configure --prefix=/opt/cross --target=aarch64-linux --enable-languages=c,c++ --disable-multilib --disable-werror
make -j8 all-gcc
make install-gcc
cd ..
mkdir -p build-glibc
cd build-glibc
../glibc-2.33/configure --prefix=/opt/cross/aarch64-linux --build="$MACHTYPE" --host=aarch64-linux --target=aarch64-linux --with-headers=/opt/cross/aarch64-linux/include --disable-multilib --disable-werror libc_cv_forced_unwind=yes
make install-bootstrap-headers=yes install-headers
make -j8 csu/subdir_lib
install csu/crt1.o csu/crti.o csu/crtn.o /opt/cross/aarch64-linux/lib
aarch64-linux-gcc -nostdlib -nostartfiles -shared -x c /dev/null -o /opt/cross/aarch64-linux/lib/libc.so
touch /opt/cross/aarch64-linux/include/gnu/stubs.h
cd ..
cd build-gcc
make -j8 all-target-libgcc
make install-target-libgcc
cd ..
cd build-glibc
make -j8
make install
cd ..
cd build-gcc
make -j8
make install
cd ..
I am now trying to use it with cmake to build a project.
I have written the following toolchain file to use when creating the makefile with CMake:
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_FIND_ROOT_PATH path/to/root/of/jetson/nano)
set(CROSS_ROOT /opt/cross/bin)
set(CMAKE_AR ${CROSS_ROOT}/aarch64-linux-ar)
set(CMAKE_ASM_COMPILER ${CROSS_ROOT}/aarch64-linux-as)
set(CMAKE_C_COMPILER ${CROSS_ROOT}/aarch64-linux-gcc)
set(CMAKE_CXX_COMPILER ${CROSS_ROOT}/aarch64-linux-g++)
set(CMAKE_LINKER ${CROSS_ROOT}/aarch64-linux-ld)
set(CMAKE_OBJCOPY ${CROSS_ROOT}/aarch64-linux-objcopy)
set(CMAKE_RANLIB ${CROSS_ROOT}/aarch64-linux-ranlib)
set(CMAKE_SIZE ${CROSS_ROOT}/aarch64-linux-size)
set(CMAKE_STRIP ${CROSS_ROOT}/aarch64-linux-strip)
set(CMAKE_GCOV ${CROSS_ROOT}/aarch64-linux-gcov)
set(CMAKE_C_FLAGS "${APP_C_FLAGS} -Wno-psabi" CACHE INTERNAL "")
set(CMAKE_CXX_FLAGS "${APP_CXX_FLAGS} ${CMAKE_C_FLAGS}" CACHE INTERNAL "")
set(CMAKE_C_FLAGS_DEBUG "-O0 -g" CACHE INTERNAL "")
set(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE INTERNAL "")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}" CACHE INTERNAL "")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}" CACHE INTERNAL "")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
The path/to/root/of/jetson/nano is a path to a root directory I created using rsync. The project compiles fine when I run cmake .. && make -j8 on the target machine.
Configuring on the host machine using cmake .. -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake succeeds with:
-- The C compiler identification is GNU 11.1.0
-- The CXX compiler identification is GNU 11.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /opt/cross/bin/aarch64-linux-gcc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /opt/cross/bin/aarch64-linux-g++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found OpenCV: /usr (found version "4.5.3")
-- Configuring done
-- Generating done
-- Build files have been written to: /path/to/my/project/build
However, when I run make -j8 I get an error on every include in the form:
fatal error: glm/gtc/matrix_transform.hpp: No such file or directory
4 | #include <glm/gtc/matrix_transform.hpp>
What's going on and how do I fix this?
No root access on cluster, install Armadillo with
make install DEST_DIR=/home/my_id/include
and now I have no idea how to do find_package(ARMADILLO REQUIRED) to set ${ARMADILLO_INCLUDE_DIRS} and${ARMADILLO_LIBRARIES}.
use CMAKE_LIBRARY_PATH and/or CMAKE_PREFIX_PATH environment variables to specify additional paths where to look for libraries and headers.
Also see cmake - find_library - custom library location but all the answers there suggest to edit CMakeLists.txt that could be slightly inconvenient sometimes.
Edit: Here's the complete working example:
alex#rhyme /var/tmp $ tar zxf armadillo-6.500.4.tar.gz
alex#rhyme /var/tmp $ cd armadillo-6.500.4
alex#rhyme /var/tmp/armadillo-6.500.4 $ mkdir build
alex#rhyme /var/tmp/armadillo-6.500.4 $ cd build
alex#rhyme tmp/armadillo-6.500.4/build $ cmake ..
-- Configuring Armadillo 6.500.4
...
-- CMAKE_INSTALL_PREFIX = /usr
-- INSTALL_LIB_DIR = /usr/lib64
-- INSTALL_INCLUDE_DIR = /usr/include
-- INSTALL_DATA_DIR = /usr/share
-- INSTALL_BIN_DIR = /usr/bin
-- Generating '/var/tmp/armadillo-6.500.4/build/ArmadilloConfig.cmake'
-- Generating '/var/tmp/armadillo-6.500.4/build/ArmadilloConfigVersion.cmake'
-- Generating '/var/tmp/armadillo-6.500.4/build/InstallFiles/ArmadilloConfig.cmake'
-- Generating '/var/tmp/armadillo-6.500.4/build/InstallFiles/ArmadilloConfigVersion.cmake'
-- Configuring done
-- Generating done
-- Build files have been written to: /var/tmp/armadillo-6.500.4/build
alex#rhyme tmp/armadillo-6.500.4/build $ make -j4
Scanning dependencies of target armadillo
[100%] Building CXX object CMakeFiles/armadillo.dir/src/wrapper.cpp.o
Linking CXX shared library libarmadillo.so
[100%] Built target armadillo
alex#rhyme tmp/armadillo-6.500.4/build $ make install DESTDIR=/var/tmp/armadillo
[100%] Built target armadillo
Install the project...
-- Install configuration: ""
-- Installing: /var/tmp/armadillo/usr/include
-- Installing: /var/tmp/armadillo/usr/include/armadillo_bits
-- Installing: /var/tmp/armadillo/usr/include/armadillo_bits/spop_htrans_bones.hpp
...
-- Installing: /var/tmp/armadillo/usr/include/armadillo_bits/subview_elem2_bones.hpp
-- Installing: /var/tmp/armadillo/usr/include/armadillo
-- Installing: /var/tmp/armadillo/usr/lib64/libarmadillo.so.6.500.4
-- Installing: /var/tmp/armadillo/usr/lib64/libarmadillo.so.6
-- Installing: /var/tmp/armadillo/usr/lib64/libarmadillo.so
-- Installing: /var/tmp/armadillo/usr/share/Armadillo/CMake/ArmadilloLibraryDepends.cmake
-- Installing: /var/tmp/armadillo/usr/share/Armadillo/CMake/ArmadilloLibraryDepends-noconfig.cmake
-- Installing: /var/tmp/armadillo/usr/share/Armadillo/CMake/ArmadilloConfig.cmake
-- Installing: /var/tmp/armadillo/usr/share/Armadillo/CMake/ArmadilloConfigVersion.cmake
alex#rhyme tmp/armadillo-6.500.4/build $ cd ../../
alex#rhyme /var/tmp $ mkdir test_armadillo_project
alex#rhyme /var/tmp $ cd test_armadillo_project
alex#rhyme /var/tmp/test_armadillo_project $ cat >CMakeLists.txt <<EOF
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
FIND_PACKAGE(Armadillo REQUIRED)
EOF
Now we're trying to build the package w/o specifying its location. CMake expectedly fails:
alex#rhyme /var/tmp/test_armadillo_project $ cmake .
-- The C compiler identification is GNU 5.3.1
-- The CXX compiler identification is GNU 5.3.1
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
CMake Error at /usr/share/CMake/Modules/FindPackageHandleStandardArgs.cmake:138 (message):
Could NOT find Armadillo (missing: ARMADILLO_LIBRARY ARMADILLO_INCLUDE_DIR)
Call Stack (most recent call first):
/usr/share/CMake/Modules/FindPackageHandleStandardArgs.cmake:374 (_FPHSA_FAILURE_MESSAGE)
/usr/share/CMake/Modules/FindArmadillo.cmake:92 (find_package_handle_standard_args)
CMakeLists.txt:3 (FIND_PACKAGE)
-- Configuring incomplete, errors occurred!
See also "/var/tmp/test_armadillo_project/CMakeFiles/CMakeOutput.log".
Now we're specifying the custom path via environment variable:
alex#rhyme /var/tmp/test_armadillo_project $ CMAKE_PREFIX_PATH=/var/tmp/armadillo/usr cmake .
-- Found Armadillo: /var/tmp/armadillo/usr/lib64/libarmadillo.so (found version "6.500.4")
-- Configuring done
-- Generating done
-- Build files have been written to: /var/tmp/test_armadillo_project
I'm pretty sure I could set CMAKE_PREFIX_PATH right in CMakeLists.txt and it would work just as with environment variable above.