Related
As the title explains, I am trying to bundle FFMPEG with my executable application.
However, I can't seem to figure out the runtime loading of the FFMPEG shared libraries. I'm not sure what is incorrect:
RPATH/RUNPATH of main project and FFMPEG libraries.
The CMake install steps.
Or just my entire approach (most likely).
This is a CMake project and in hope of finally finding a "standard solution", I am going to include everything needed to reproduce this issue.
CMakeLists.txt:
cmake_minimum_required(VERSION 3.21) # Required for the install(RUNTIME_DEPENDENCY_SET...) subcommand
project(cmake-demo LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
set(CMAKE_CXX_EXTENSIONS NO)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN YES)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# Setup CMAKE_PREFIX_PATH for `find_package`
list(APPEND CMAKE_PREFIX_PATH ${CMAKE_CURRENT_LIST_DIR}/vendor/install)
find_package(PkgConfig REQUIRED)
pkg_check_modules(ffmpeg REQUIRED IMPORTED_TARGET libavdevice libavfilter libavformat libavcodec
libswresample libswscale libavutil)
# Setup variable representing the vendor install directory
set(VENDOR_PATH ${CMAKE_CURRENT_LIST_DIR}/vendor/install)
# Set RPATH to the dependency install tree
set(CMAKE_INSTALL_RPATH $ORIGIN/../deps)
# Add our executable target
add_executable(demo main.cpp)
target_include_directories(demo PRIVATE ${VENDOR_PATH}/include)
target_link_libraries(demo PRIVATE PkgConfig::ffmpeg)
include(GNUInstallDirs)
install(TARGETS demo RUNTIME_DEPENDENCY_SET runtime_deps)
install(RUNTIME_DEPENDENCY_SET runtime_deps
DESTINATION ${CMAKE_INSTALL_PREFIX}/deps
# DIRECTORIES ${VENDOR_PATH}/lib
POST_EXCLUDE_REGEXES "^/lib" "^/usr" "^/bin")
main.cpp:
extern "C"{
#include <libavcodec/avcodec.h>
}
#include <iostream>
int main(int argc, char* argv[])
{
std::cout << "FFMPEG AVCODEC VERSION: " << avcodec_version() << std::endl;
return 0;
}
Instructions:
Setup FFMPEG (this can take awhile...):
git clone https://github.com/FFmpeg/FFmpeg.git --recurse-submodules --shallow-submodules vendor/src/ffmpeg
git checkout release/5.0
export INSTALL_PATH=$PWD/vendor/install
cd vendor/src/ffmpeg
./configure --prefix=$INSTALL_PATH --enable-shared --disable-static --enable-pic --enable-lto --extra-cflags=-fPIC --extra-ldexeflags=-pie
# WITH RPATH (HARDCODED TO VENDOR install directory)
# ./configure --prefix=$INSTALL_PATH --enable-shared --disable-static --enable-pic --enable-lto --extra-cflags=-fPIC --extra-ldflags=-Wl,-rpath,$INSTALL_PATH/lib --extra-ldexeflags=-pie
make -j16 V=1
make install
cd ../../..
CMake Commands:
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=install
cmake --build build -j16 #-v
cmake --install build
Cleanup between steps:
# Run from top-level dir of project
rm -rf build install
rm -rf vendor/install # ONLY if you need to modify the FFMPEG step.
Investigation:
Following the direction of this post I set the RPATH/RUNPATH of the executable to $ORIGIN/../deps and no RPATH on the FFMPEG libraries.
When I do this, the cmake install step fails complaining that libavutil.so cannot be resolved in the install(RUNTIME_DEPENDENCY_SET...) function. This does make sense because the generated cmake_install.cmake script in the build directory is moving the demo executable to the install directory and performing file(RPATH_CHANGE...) on the executable prior to doing the runtime dependency set analysis. According to the CMake documentation here and using readelf -d demo the RUNPATH of the executable is $ORIGIN/../deps and only case #1 from the docs apply here so the library isn't found at all.
From the CMake documentation referenced in 1, there is a DIRECTORIES argument for the install(RUNTIME_DEPENDENCY_SET...) function that can be used as a search path. When combining the setup in 1, uncommenting this in CMakeLists.txt and rerunning all the CMake commands, the installation is successful (although as documented, CMake does emit warnings for all the dependencies found using DIRECTORIES). However, running the executable (i.e. ./install/bin/demo) is unsuccessful because the runtime loader cannot locate libswresample.so. Debugging into this a little further, I ran export LD_DEBUG=libs and tried to relaunch the executable. This shows that the runtime loader is finding libavcodec.so using the $ORIGIN/../deps RUNPATH from demo. However, when searching for the transitive dependency (i.e. libavcodec.so's dep. on libswresample.so), the RUNPATH of demo is NOT searched, instead the loader falls back to the system path and the library is not found.
I was able to satisfy CMake and the loader by setting the RPATH on the FFMPEG libraries and not using the DIRECTORIES argument with the CMake install(RUNTIME_DEPENDENCY_SET...) sub-command. CMake runs without any warnings and the executable loads/runs as expected. However, this is NOT a viable solution because when inspecting the libraries in the install/deps folder with ldd, the libswresample.so and other libraries are pointing back to the vendor/install directory which is not going to be present in the bundle when deployed.
Does anyone know what the standard approach is or what I am missing above? I am open to any and all suggestions/tools but I am doing this in an attempt to learn what is "standard practice" and am hoping to extend this to a cross-platform solution (i.e Windows/macOS). As a result, I would like to avoid messing with the system level loader configuration (ldconfig).
Thanks!
Reproducing the Issue
To try to reproduce your problem, I actually discarded all CMake stuff and just compiled main.cpp from the command line. I think you'll agree that the root of the issue is in the ffmpeg build.
g++ -I vendor/install/include -c -o main.o main.cpp
g++ -L vendor/install/lib -o main main.o -lavcodec
The output looked like this:
usr/bin/ld: warning: libswresample.so.4, needed by vendor/install/lib/libavcodec.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: warning: libavutil.so.57, needed by vendor/install/lib/libavcodec.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: vendor/install/lib/libavcodec.so: undefined reference to `av_opt_set_int#LIBAVUTIL_57'
/usr/bin/ld: vendor/install/lib/libavcodec.so: undefined reference to `av_get_picture_type_char#LIBAVUTIL_57'
# many more lines of undefined references
You can make this go away by adding -rpath-link...
g++ -Wl,-rpath-link,vendor/install/lib -L vendor/install/lib -o main main.o -lavcodec
but the executable fails with this error:
./main: error while loading shared libraries: libavcodec.so.59: cannot open shared object file: No such file or directory
If you use -rpath instead of -rpath-link, you get this error instead:
./main: error while loading shared libraries: libswresample.so.4: cannot open shared object file: No such file or directory
This last error is because libavcodec.so references libwresample.so, and doesn't have it in its RPATH. main finds libavcodec.so successfully, but then the dynamic linker gets stuck.
Solving the Issue
From what I can tell, the ffmpeg configure script sanitizes the arguments passed in via --extra-ldflags and it's variants. No matter how hard you try, I don't think it will allow you to pass in a $ sign in this way. To pass in un-sanitized arguments, you should set LDFLAGS (and its variants) in the environment when you call configure. The end goal is to get the string -Wl,-rpath,'$ORIGIN' into the command to create each library, which means we want that value assigned to LDSOFLAGS. Let's start by passing it in straight:
LDSOFLAGS=-Wl,-rpath,'$ORIGIN' ../configure --prefix=$INSTALL_PATH --enable-shared --disable-static --enable-pic --enable-lto --extra-cflags=-fPIC --extra-ldexeflags=-pie
Looking in src/build/ffbuild/config.mak we see the following line:
LDSOFLAGS=-Wl,-rpath,$ORIGIN
In this case, the single quotes were interpreted by the shell running the configure command, so they don't appear in the generated makefile.
If we escape the single quotes, however, then the shell will expand the $ORIGIN environment variable (empty, in this case), and produce this line:
LDSOFLAGS=-Wl,-rpath,''
If you put "real" single quotes inside the escaped ones, however...
LDSOFLAGS=-Wl,-rpath,\''$ORIGIN'\' ../configure --prefix=$INSTALL_PATH --enable-shared --disable-static --enable-pic --enable-lto --extra-cflags=-fPIC --extra-ldexeflags=-pie
it produces the correct line:
LDSOFLAGS=-Wl,-rpath,'$ORIGIN'
Now, however, there is the problem that make also uses $ signs. Typically we could escape the $ sign by replacing it with $$. However, you can see in src/ffbuild/library.mak that LDSOFLAGS is used inside of define RULES, which is then applied with the line $(eval $(RULES)). This will expand LDSOFLAGS and any variables inside of it immediately, which means the $$ will be replaced with a single $ in the final version of the recipe, so, we need to use four $ signs to survive the expansion in the eval as well as the expansion when the recipe is executed.
LDSOFLAGS=-Wl,-rpath,\''$$$$ORIGIN'\' ../configure --prefix=$INSTALL_PATH --enable-shared --disable-static --enable-pic --enable-lto --extra-cflags=-fPIC --extra-ldexeflags=-pie
For completeness, let's also define LDEXEFLAGS, so that the ffmpeg executable works properly. Notice that LDEXEFLAGS only requires two $ signs (you would have to look in the makefiles to know this).
LDEXEFLAGS=-Wl,-rpath,\''$$ORIGIN/../lib'\' LDSOFLAGS=-Wl,-rpath,\''$$$$ORIGIN'\' ../configure --prefix=$INSTALL_PATH --enable-shared --disable-static --enable-pic --enable-lto --extra-cflags=-fPIC --extra-ldexeflags=-pie
After building and installing, the last thing to do is to make sure main also has the correct RPATH:
g++ -Wl,-rpath,'$ORIGIN/vendor/install/lib' -L vendor/install/lib -o main main.o -lavcodec
And here's the result:
$ ./main
FFMPEG AVCODEC VERSION: 3871332
I am a novice in C++ programming, now having to build the OpenCV from source. I am getting an error related to the cudatoolkit installation
[ 13%] Built target opencv_cudev
[ 13%] Building NVCC (Device) object modules/core/CMakeFiles/cuda_compile.dir/src/cuda/cuda_compile_generated_gpu_mat.cu.o
nvcc fatal : Path to libdevice library not specified
CMake Error at cuda_compile_generated_gpu_mat.cu.o.cmake:266 (message):
Error generating file
/home/bruce/opencv-4.2.0/build/modules/core/CMakeFiles/cuda_compile.dir/src/cuda/./cuda_compile_generated_gpu_mat.cu.o
I look inside the cuda_compile_generated_gpu_mat.cu.o.cmake file and see the following lines.
# Generate the code
cuda_execute_process(
"Generating ${generated_file}"
COMMAND "${CUDA_NVCC_EXECUTABLE}"
"${source_file}"
${format_flag} -o "${generated_file}"
${CCBIN}
${nvcc_flags}
${nvcc_host_compiler_flags}
${CUDA_NVCC_FLAGS}
-DNVCC
${CUDA_NVCC_INCLUDE_ARGS}
)
I want to dig into where it's looking for the libdevice library. I don't know the technique for printing out the meaning of all these parameters. How do I print them out as I execute make?
If you want to debug this, and print the values in each of these CMake variables, you can add the message command to this CMake file:
# Generate the code
cuda_execute_process(
"Generating ${generated_file}"
COMMAND "${CUDA_NVCC_EXECUTABLE}"
"${source_file}"
${format_flag} -o "${generated_file}"
${CCBIN}
${nvcc_flags}
${nvcc_host_compiler_flags}
${CUDA_NVCC_FLAGS}
-DNVCC
${CUDA_NVCC_INCLUDE_ARGS}
)
# Print all the above variables to the console.
message("generated_file: ${generated_file}")
message("CUDA_NVCC_EXECUTABLE: ${CUDA_NVCC_EXECUTABLE}")
message("source_file: ${source_file}")
message("format_flag: ${format_flag}")
message("CCBIN: ${CCBIN}")
message("nvcc_flags: ${nvcc_flags}")
message("nvcc_host_compiler_flags: ${nvcc_host_compiler_flags}")
message("CUDA_NVCC_FLAGS: ${CUDA_NVCC_FLAGS}")
message("CUDA_NVCC_INCLUDE_ARGS: ${CUDA_NVCC_INCLUDE_ARGS}")
If you can modify how cmake is called from the command line, you can add the trace-expand option to print all the CMake calls, and expand the variables used:
cmake --trace-expand ..
I want to integrate clang-tidy to our C and C++, CMake based project which is compiled using a custom GCC toolchain.
I've tried following this tutorial, setting CMAKE_CXX_CLANG_TIDY. I've also tried generating a compilation database by setting CMAKE_EXPORT_COMPILE_COMMANDS to ON and pointing run-clang-tidy.py to its directory.
In both cases, I've encountered (the same) few errors that are probably related to differences between Clang and GCC:
Some warning flags that are enabled in the CMake files are not supported in Clang but are supported in GCC (like -Wlogical-op). As the compiler is GCC, the file builds correctly, and the flag is written to the compilation database, but clang-tidy complains about it.
clang-tidy complains some defines and functions are unavailable, even though the code compiles just fine. As an example, the android-cloexec-open check suggested using O_CLOEXEC to improve security and force the closing of files, but trying to use this define leads to an undefined identifier error (even though our GCC compiles the code).
As an example to a function that is not found, there is clock_gettime.
Our code compiles with the C11 standard and C++14 standard, without GNU extensions:
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_C_EXTENSIONS OFF)
set(CMAKE_CXX_EXTENSIONS OFF)
The custom toolchain is a cross-compilation toolchain which runs on Linux and compiles to FreeBSD.
Is there a way to disable the passing of some flags by CMake to clang-tidy? Am I using clang-tidy wrong?
I suspect this issue is related to disabling GNU extensions, using a cross-compilation toolchain, and some feature-test-macro which is not defined by default in Clang but is defined with GCC (e.g. _GNU_SOURCE/_POSIX_SOURCE). If this is the case, how can I check it? If not, should I use clang-tidy differently?
EDIT
As #pablo285 asked, here are 2 warnings I get for a single file, and then as I added --warnings-as-errors=*, the build stops:
error: unknown warning option '-Wlogical-op' ; did you mean '-Wlong-long'? [clang-diagnostic-error]
<file path>: error: use of undeclared identifier 'O_CLOEXEC' [clang-diagnostic-error]
O_WRONLY | O_CLOEXEC
^
I decided to write a python script that will replace clang-tidy, receive the commandline from CMake and edit it to fix various errors. Here are the modification to the commandline I tried:
Remove none clang compile flags
This helps with things like the first warning, as now I don't pass flags that clang doesn't know. It seems like I can't configure CMake to pass different set of flags to GCC and to clang-tidy, so if anyone is familiar with some solution to this problem, I'll be happy to hear!
I changed the include directories that are passed to clang-tidy
As mentioned in the post, I use a custom toolchain (which cross-compiles). I used this post and Python to extract the list of standard include directories, and added them to the flag list as a list of -isystem <dir>. I also added -nostdinc so that clang-tidy won't try to look on his own headers instead of mine
This helped with the issue above, as now various defines such as O_CLOEXEC is defined in the toolchain's headers, but as my toolchain is based on GCC, clang couldn't parse the <type_traits> header which includes calls to many compiler intrinsics
I'm not sure what's the best approach in this case
#shycha: Thanks for the tip, I'll try disabling this specific check and I'll edit this post again
Ok, I think that I have a solution. After a couple of evenings I was able to make it work.
In general I compile like this
rm -rf build
mkdir build
cd build
cmake -C ../cmake-scripts/clang-tidy-all.cmake .. && make
Where cmake-scripts directory contains:
clang-tidy-all.cmake
toolchain_arm_clang.cmake
The two important files are listed below.
But what is more important, is how you need to compile this.
First, toolchain_arm_clang.cmake is referenced directly from clang-tidy-all.cmake via set(CMAKE_TOOLCHAIN_FILE ...). It must be, however, referenced from the point of view of the building directory, so if you use multiple levels of build-dirs, e.g.: build/x86, build/arm, build/darwin, etc., then you must modify that path accordingly.
Second, the purpose of set(CONFIG_SCRIPT_PRELOADED ...) is to be sure that the config script was pre-loaded, i.e., cmake -C ../cmake-scripts/clang-tidy-all.cmake ..
Typically, you would want to have something like this somewhere in your CMakeLists.txt file:
message(STATUS "CONFIG_SCRIPT_PRELOADED: ${CONFIG_SCRIPT_PRELOADED}")
if(NOT CONFIG_SCRIPT_PRELOADED)
message(FATAL_ERROR "Run cmake -C /path/to/cmake.script to preload a config script!")
endif()
Third, there is /lib/ld-musl-armhf.so.1 hard-coded in set(CMAKE_LINKER_ARM_COMPAT_STATIC ...); on the development box that I use, it points to /lib/libc.so, so it might by OK to use /lib/libc.sh instead. I've never tried.
Fourth, using set(CMAKE_C_LINK_EXECUTABLE ...) and set(CMAKE_LINKER_ARM_COMPAT_STATIC ...) was because CMake was complaining about some linking problems during checking the compiler, i.e., before even running make.
Fifth, I was only compiling C++ code, so if you need to compile some C, then it might be required to also properly configure set(CMAKE_C_CREATE_SHARED_LIBRARY ...), but I have no idea whether there is such a config option.
General Advice
Do not integrate it immediately. First test some simple CMake project with one library (preferably a C++ one) and make it work, then add the second library, but in C, tweak it again. And only after that incorporate it into the code base.
Toolchain
I used a custom toolchain with GCC 8.3.0 and musl C library, so locations of some files might be different for other toolchains.
Custom CMake
Some variables, like (already mentioned) CONFIG_SCRIPT_PRELOADED, EXPORT_PACKAGE_TO_GLOBAL_REGISTRY, DO_NOT_BUILD_TESTS, or DO_NOT_BUILD_BENCHMARKS are not generic CMake options, i.e., I use them only in my CMakeLists.txt, so you can safely ignore them.
Variables that are unset at the end of each *.cmake file, e.g., build_test, extra_clang_tidy_unchecks_for_tests_only, don't need to be present in the project's main CMakeLists.txt.
Clang
$ clang --version
clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4650b2f36949407ef25686440e3d65ac47709deb)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /opt/local/bin
Files
clang-tidy-all.cmake:
set(ALL_CXX_WARNING_FLAGS --all-warnings -Weverything -Wno-c++98-compat -Wno-c++98-c++11-compat -Wno-c++98-c++11-c++14-compat -Wno-padded -Wno-c++98-compat-pedantic)
set(CXX_COMPILE_OPTIONS "-std=c++17;-O3;${ALL_CXX_WARNING_FLAGS}" CACHE INTERNAL "description")
set(CMAKE_CROSSCOMPILING True)
set(CMAKE_TOOLCHAIN_FILE "../cmake-scripts/toolchain_arm_clang.cmake" CACHE FILEPATH "CMake toolchain file")
set(CONFIG_SCRIPT_PRELOADED true CACHE BOOL "Ensures that config script was preloaded")
set(build_test False)
if(build_test)
message(STATUS "Using test mode clang-tidy checks!")
set(extra_clang_tidy_unchecks_for_tests_only ",-google-readability-avoid-underscore-in-googletest-name,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-special-member-functions")
endif()
set(CMAKE_CXX_CLANG_TIDY "clang-tidy;--enable-check-profile;--checks=-*,abseil-string-find-startswith,bugprone-*,cert-*,clang-analyzer-*,cppcoreguidelines-*,google-*,hicpp-*,llvm-*,misc-*,modernize-*,-modernize-use-trailing-return-type,performance-*,readability-*,-readability-static-definition-in-anonymous-namespace,-readability-simplify-boolean-expr,portability-*${extra_clang_tidy_unchecks_for_tests_only}" CACHE INTERNAL "clang-tidy")
message(STATUS "build_test: ${build_test}")
message(STATUS "extra_clang_tidy_unchecks_for_tests_only: ${extra_clang_tidy_unchecks_for_tests_only}")
message(STATUS "CMAKE_CXX_CLANG_TIDY: ${CMAKE_CXX_CLANG_TIDY}")
# We want to skip building tests when clang-tidy is run (it takes too much time and serves nothing)
if(DEFINED CMAKE_CXX_CLANG_TIDY AND NOT build_test)
set(DO_NOT_BUILD_TESTS true CACHE BOOL "Turns OFF building tests")
set(DO_NOT_BUILD_BENCHMARKS true CACHE BOOL "Turns OFF building benchmarks")
endif()
unset(build_test)
unset(extra_clang_tidy_unchecks_for_tests_only)
set(EXPORT_PACKAGE_TO_GLOBAL_REGISTRY "OFF" CACHE INTERNAL "We don't export clang-tidy-all version to global register")
toolchain_arm_clang.cmake:
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_VERSION 4.14.0)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(gcc_version 8.3.0)
set(x_tools "/opt/zynq/xtl")
set(CMAKE_C_COMPILER "clang" CACHE INTERNAL STRING)
set(CMAKE_CXX_COMPILER "clang++" CACHE INTERNAL STRING)
set(CMAKE_RANLIB "llvm-ranlib" CACHE INTERNAL STRING)
set(CMAKE_AR "llvm-ar" CACHE INTERNAL STRING)
set(CMAKE_AS "llvm-as" CACHE INTERNAL STRING)
set(CMAKE_LINKER "ld.lld" CACHE INTERNAL STRING)
execute_process(
COMMAND bash -c "dirname `whereis ${CMAKE_LINKER} | tr -s ' ' '\n' | grep ${CMAKE_LINKER}`"
OUTPUT_VARIABLE cmake_linker_dir
)
string(REGEX REPLACE "\n$" "" cmake_linker_dir "${cmake_linker_dir}")
set(cmake_linker_with_dir "${cmake_linker_dir}/${CMAKE_LINKER}" CACHE INTERNAL STRING)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -iwithsysroot /include/c++/${gcc_version} -iwithsysroot /include/c++/${gcc_version}/arm-linux-musleabihf" CACHE INTERNAL STRING)
set(CMAKE_SYSROOT ${x_tools}/arm-linux-musleabihf)
set(CMAKE_FIND_ROOT_PATH ${x_tools}/arm-linux-musleabihf)
set(CMAKE_INSTALL_PREFIX ${x_tools}/arm-linux-musleabihf)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE NEVER)
set(triple arm-linux-musleabihf)
set(CMAKE_LIBRARY_ARCHITECTURE ${triple})
set(CMAKE_C_COMPILER_TARGET ${triple})
set(CMAKE_CXX_COMPILER_TARGET ${triple})
set(lib_path_arm ${x_tools}/arm-linux-musleabihf/lib)
## Bootstrap library stuff:
set(Scrt1_o ${lib_path_arm}/Scrt1.o)
set(crti_o ${lib_path_arm}/crti.o)
set(crtn_o ${lib_path_arm}/crtn.o)
set(lib_path_gcc ${x_tools}/lib/gcc/${triple}/${gcc_version})
set(crtbeginS_o ${lib_path_gcc}/crtbeginS.o)
set(crtendS_o ${lib_path_gcc}/crtendS.o)
# Clang as linker
# --no-pie disable position independent executable, which is required when building
# statically linked executables.
set(CMAKE_CXX_LINK_EXECUTABLE "clang++ --target=${triple} -Wl,--no-pie --sysroot=${CMAKE_SYSROOT} ${CMAKE_CXX_FLAGS} -fuse-ld=${cmake_linker_with_dir} <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> <OBJECTS> -o <TARGET> ")
set(CMAKE_CXX_CREATE_SHARED_LIBRARY "clang++ -Wl, --target=${triple} --sysroot=${CMAKE_SYSROOT} ${CMAKE_CXX_FLAGS} -fuse-ld=${cmake_linker_with_dir} -shared <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> <OBJECTS> -o <TARGET> ")
#
# Do not use CMAKE_CXX_CREATE_STATIC_LIBRARY -- it is created automatically
# by cmake using ar and ranlib
#
#set(CMAKE_CXX_CREATE_STATIC_LIBRARY "clang++ -Wl,--no-pie,--no-export-dynamic,-v -v --target=${triple} --sysroot=${CMAKE_SYSROOT} ${CMAKE_CXX_FLAGS} -fuse-ld=ld.lld <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> <OBJECTS> -o <TARGET> ")
## Linker as linker
set(CMAKE_LINKER_ARM_COMPAT_STATIC "-pie -EL -z relro -X --hash-style=gnu --eh-frame-hdr -m armelf_linux_eabi -dynamic-linker /lib/ld-musl-armhf.so.1 ${Scrt1_o} ${crti_o} ${crtbeginS_o} -lstdc++ -lm -lgcc_s -lgcc -lc ${crtendS_o} ${crtn_o}")
set(CMAKE_C_LINK_EXECUTABLE "${CMAKE_LINKER} ${CMAKE_LINKER_ARM_COMPAT_STATIC} <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> <OBJECTS> -o <TARGET>")
# Debian bug 708744(?)
#include_directories("${CMAKE_SYSROOT}/usr/include/")
#include_directories("${CMAKE_SYSROOT}/usr/include/c++/${gcc_version}")
#include_directories("${CMAKE_SYSROOT}/usr/include/c++/${gcc_version}/${triple}")
## Clang workarounds:
set(toolchain_lib_dir_0 "${CMAKE_SYSROOT}/lib")
set(toolchain_lib_dir_1 "${CMAKE_SYSROOT}/../lib")
set(toolchain_lib_dir_2 "${CMAKE_SYSROOT}/../lib/gcc/${triple}/${gcc_version}")
set(CMAKE_TOOLCHAIN_LINK_FLAGS "-L${toolchain_lib_dir_0} -L${toolchain_lib_dir_1} -L${toolchain_lib_dir_2}")
## CMake workarounds
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_TOOLCHAIN_LINK_FLAGS} CACHE INTERNAL "exe link flags")
set(CMAKE_MODULE_LINKER_FLAGS ${CMAKE_TOOLCHAIN_LINK_FLAGS} CACHE INTERNAL "module link flags")
set(CMAKE_SHARED_LINKER_FLAGS ${CMAKE_TOOLCHAIN_LINK_FLAGS} CACHE INTERNAL "shared link flags")
unset(cmake_linker_with_dir)
unset(cmake_linker_dir)
Maybe not exactly what you're looking for but I'm using this in CMakeLists.txt:
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_custom_target(lint
COMMAND sh -c "run-clang-tidy -header-filter=.* -checks=`tr '\\n' , <${CMAKE_SOURCE_DIR}/checks.txt` >lint.out 2>lint.err"
COMMAND sh -c "grep warning: lint.out || true"
COMMAND ls -lh ${CMAKE_BINARY_DIR}/lint.out
VERBATIM
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
This creates a separate build target (make lint) for the clang-tidy check. clang-tidy takes a long time for my project so I don't want to run it during every build; make lint can be run manually if required, and it's also executed in a CI job after every push to the repo (in a way that makes the CI pipeline fail, blocking the merge, if there are any findings).
The output of make lint is the list of clang-tidy findings with as little context as possible. The full output, including context for findings, is in lint.out, and error messages are in lint.err, both of which I'm saving as CI artefacts.
checks.txt is a text file in the project root that defines which clang-tidy checks to activate, like so:
*
-altera-id-dependent-backward-branch
-altera-struct-pack-align
-altera-unroll-loops
-android-*
The first line enables all available checks, the other lines disable checks that I don't want.
Will only work in a Unix-like system of course.
I'm trying to build a NaCl extension on 64-bit Windows 8.1 using CMake. The same code works on Ubuntu without any problems. Everything goes well until CMake tries to link with this command:
cmake -E cmake_link_script link.txt
CMake: Error running link command: %1 is not a valid Win32 application
The link.txt is as follows:
C:/nacl_sdk/pepper_39/toolchain/win_pnacl/bin/pnacl-ar cr libfoo.a CMakeFiles/foo.dir/Foo.cc.o
C:/nacl_sdk/pepper_39/toolchain/win_pnacl/bin/pnacl-ranlib libfoo.a
This happens with both NMake and Unix makefile generators (the NaCl SDK contains make.exe for Windows).
If I run those commands manually, they succeed. What could be wrong here?
Just like eugensk00 suggested adding ".bat" in toolchain definitions seems to work. It is required to add both for ar and ranlib though:
set(CMAKE_AR "${PLATFORM_PREFIX}/bin/pnacl-ar.bat" CACHE STRING "")
set(CMAKE_RANLIB "${PLATFORM_PREFIX}/bin/pnacl-ranlib.bat" CACHE STRING "")
I have c++ project that was smoothly running on a given machine, and now I am trying to compile it on another one with the same operating system (Xubuntu 14.04).
I've installed all the dependencies and I'am using cmake to build the project, although it stops with the following error:
Determining if the function pthread_create exists in the pthreads failed with the following output:
...
/usr/bin/ld: cannot find -lpthreads
The cmakelists.txt lines that include the compiler flags are as follows:
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -lpthread -DNDEBUG -DEIGEN_MPL2_ONLY")
set(CMAKE_C_FLAGS_DEBUG "-g -O0 -Wall -lpthread -DEIGEN_MPL2_ONLY")
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -O3 -lpthread -I/usr/include/freetype2 -DNDEBUG -DEIGEN_MPL2_ONLY")
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -Wall -lpthread -I/usr/include/freetype2 -DEIGEN_MPL2_ONLY")
I have done some research and have already tried the following:
-used -pthread/-threads/-thread/-lpthreads instead of -lpthread, which does not solve the issue and makes the build stop without finding the following package:
find_package (Threads)
changed the order of -lpthread in the cmakelists line above, which gives the same error
used different versions o gcc/g++: tried 4.4, 4.6 and 4.8, without any change
created a symbolic link to libpthread.so in /usr/lib/, without any change
I would appreciate some help, since I am already short on ideas on what to try next.
Edit 1
The library is where it should:
$ find /lib -name "*pthread*"
/lib/x86_64-linux-gnu/libpthread-2.19.so
/lib/x86_64-linux-gnu/libpthread.so.0
The pthread_create is also found:
$ nm /lib/x86_64-linux-gnu/libpthread.so.0 | grep "pthread_create"
0000000000008430 t __pthread_create_2_1
00000000000081430 T pthread_create##GLIBC_2.2.5
I have also verified that both libpthread-stubs0 and libc6-dev are present.
Edit 2
This is part of the FindThreads.cmake file content, located in /usr/share/cmake-2.8/Modules/:
if(CMAKE_HAVE_SPROC_H AND NOT CMAKE_THREAD_PREFER_PTHREAD)
# We have sproc
set(CMAKE_USE_SPROC_INIT 1)
else()
# Do we have pthreads?
CHECK_INCLUDE_FILES("pthread.h" CMAKE_HAVE_PTHREAD_H)
if(CMAKE_HAVE_PTHREAD_H)
#
# We have pthread.h
# Let's check for the library now.
#
set(CMAKE_HAVE_THREADS_LIBRARY)
if(NOT THREADS_HAVE_PTHREAD_ARG)
# Check if pthread functions are in normal C library
CHECK_SYMBOL_EXISTS(pthread_create pthread.h CMAKE_HAVE_LIBC_CREATE)
if(CMAKE_HAVE_LIBC_CREATE)
set(CMAKE_THREAD_LIBS_INIT "")
set(CMAKE_HAVE_THREADS_LIBRARY 1)
set(Threads_FOUND TRUE)
endif()
if(NOT CMAKE_HAVE_THREADS_LIBRARY)
# Do we have -lpthreads
CHECK_LIBRARY_EXISTS(pthreads pthread_create "" CMAKE_HAVE_PTHREADS_CREATE)
if(CMAKE_HAVE_PTHREADS_CREATE)
set(CMAKE_THREAD_LIBS_INIT "-lpthreads")
set(CMAKE_HAVE_THREADS_LIBRARY 1)
set(Threads_FOUND TRUE)
endif()
# Ok, how about -lpthread
CHECK_LIBRARY_EXISTS(pthread pthread_create "" CMAKE_HAVE_PTHREAD_CREATE)
if(CMAKE_HAVE_PTHREAD_CREATE)
set(CMAKE_THREAD_LIBS_INIT "-lpthread")
set(CMAKE_HAVE_THREADS_LIBRARY 1)
set(Threads_FOUND TRUE)
endif()
if(CMAKE_SYSTEM MATCHES "SunOS.*")
# On sun also check for -lthread
CHECK_LIBRARY_EXISTS(thread thr_create "" CMAKE_HAVE_THR_CREATE)
if(CMAKE_HAVE_THR_CREATE)
set(CMAKE_THREAD_LIBS_INIT "-lthread")
set(CMAKE_HAVE_THREADS_LIBRARY 1)
set(Threads_FOUND TRUE)
endif()
endif()
endif()
endif()
if(NOT CMAKE_HAVE_THREADS_LIBRARY)
# If we did not found -lpthread, -lpthread, or -lthread, look for -pthread
if("THREADS_HAVE_PTHREAD_ARG" MATCHES "^THREADS_HAVE_PTHREAD_ARG")
message(STATUS "Check if compiler accepts -pthread")
try_run(THREADS_PTHREAD_ARG THREADS_HAVE_PTHREAD_ARG
${CMAKE_BINARY_DIR}
${CMAKE_ROOT}/Modules/CheckForPthreads.c
CMAKE_FLAGS -DLINK_LIBRARIES:STRING=-pthread
COMPILE_OUTPUT_VARIABLE OUTPUT)
if(THREADS_HAVE_PTHREAD_ARG)
if(THREADS_PTHREAD_ARG STREQUAL "2")
set(Threads_FOUND TRUE)
message(STATUS "Check if compiler accepts -pthread - yes")
else()
message(STATUS "Check if compiler accepts -pthread - no")
file(APPEND
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
"Determining if compiler accepts -pthread returned ${THREADS_PTHREAD_ARG} instead of 2. The compiler had the following output:\n${OUTPUT}\n\n")
endif()
else()
message(STATUS "Check if compiler accepts -pthread - no")
file(APPEND
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
"Determining if compiler accepts -pthread failed with the following output:\n${OUTPUT}\n\n")
endif()
endif()
if(THREADS_HAVE_PTHREAD_ARG)
set(Threads_FOUND TRUE)
set(CMAKE_THREAD_LIBS_INIT "-pthread")
endif()
endif()
endif()
endif()
Edit 3
Used a minimal Cmakelists.txt as follows:
cmake_minimum_required (VERSION 2.4)
find_package(Threads)
Which produced the following output:
-- Looking for include file pthread.h
-- Looking for include file pthread.h - found
-- Looking for pthread_create
-- Looking for pthread_create - not found.
-- 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
The problem was happening when running cmake. Though, in this case cmake was not the problem the error was silent and the -lpthreads related error/warning was the only thing being written to the cmake error log file, although that was not causing any issue.
I've done a minimal version of the cmakelists.txt and started testing it line by line until I found which package was causing it to stop: finally I found it was a version mismatch...
Hint: search for the actual error message
Typically you'd look for the last error message. However, this (often useful) strategy in such cases leads astray.
What you are looking at is the CMakeCache.txt, the CMakeOutput.log or the CMakeError.log. How comes? When some of the macros or tests in the configure phase fails, CMake "helpfully" dumps these files to the output. Unfortunately, these files can be thousands of lines long, and typically contain lots of "*** Error: xyz" entries, for various configure checks. The one for "-lpthreads" just accidentally happened to be the last one in the log...
Solution: go through the log from the top, identify the section with the configure checks, find the last configure check prior to the point, where CMake identifies failure and dumps its logs. You might also try so search for the text "Configuring incomplete, errors occurred!"
Typically you'll either find a very precise actual error message there, or at least you find the name / path of the macro or function called last, and this allows you to pinpoint down what actually went wrong.
at an Ubuntu 18.04.1 LTS this installation gave me all the files needed:
apt -y install libboost-tools-dev libboost-thread1.62-dev magics++
/usr/lib/x86_64-linux-gnu/libpthread.a
/usr/lib/x86_64-linux-gnu/libpthread.so
/usr/lib/x86_64-linux-gnu/libpthread_nonshared.a
no more errors "/usr/bin/ld: cannot find -lpthreads" after
Edit1:
All references below is for Ubuntu.
Package named libpthread-stubs0 is likely only a stub, so won't have the pthread_create function.
Do you have this?
$ find /lib -name "*pthread*"
/lib/x86_64-linux-gnu/libpthread-2.15.so
/lib/x86_64-linux-gnu/libpthread.so.0
Check for the symbol pthread_create which should exist.
$ nm /lib/x86_64-linux-gnu/libpthread.so.0 | grep "pthread_create"
0000000000008140 t __pthread_create_2_1
0000000000008140 T pthread_create##GLIBC_2.2.5
If that doesn't work, you may need the dev version of pthread which is in libc6-dev. You can search for the package contents which has libpthread.so in http://packages.ubuntu.com/.
Note: Also, it's failing on -lpthreads. Should it be -lpthread instead (without the s)?
Edit 2
Create a simple CMakeLists.txt with the following and run cmake.
cmake_minimum_required (VERSION 2.8.7)
find_package(Threads)
What's the output? Does it find pthread?
My output is:
-- Looking for include file pthread.h
-- Looking for include file pthread.h - found
-- Looking for pthread_create
-- Looking for pthread_create - not found.
-- 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
This appears to be a long-standing CMake bug. Something else is going wrong, CMake gets confused, and reports this spurious problem instead of the real error.
Look for "thread" in your CMakeLists.txt file and temporarily remove that.
In my case, this immediately pinpointed a library (or rather, its development package) that was missing. Installed it, added it to debian/control's Build-Depends: section, recompiled, everything worked.
on ubuntu 18.04 I solved as below.
$ sudo apt-get install libboost-all-dev
I had the exact same problem, with the minimal Cmakelists.txt giving me the same output.
To solve this, just upgrade cmake to the lastest version (3.15 in my case)
I found out what was causing my issue. I initially did it with cmake2, but the project needed cmake3. I changed it to cmake3, but it didn't do a clean build, so some leftover garbage was messing everything up. When I cleaned everything and used cmake3 it worked.
I also meet this issue. Exactly the same situation: have pthread lib under /lib/x86..., but the find_package() always gives a "can not find lpthread error".
And after some check and consulation to my friend, we find that in my case, I build the cmake from source code and let the cmake link search path be wrong. So we deinstall the self-buid version and reinstall the cmake in a "correct" way by adding the apt source and using apt get install. That solves my issue. Hope this could help guys in the same situation.
Kindly try to install one dependency glibc-static
On Ubuntu you can try apt-get install build-essential
On other linux you may install package similar to glibc-static.
This question has many answers; it seems that many obscure issues can cause this bug. The other answers didn't work for me, and though my Output/Error logs were fairly clean, I couldn't find any additional error messages or failures there. So I'll add what I did in case it helps anyone who is in my situation.
In short, my problem was fixed when I deleted the entire build directory and rebuilt from scratch. Deleting only the CMakeCache wasn't enough. If you have this issue, try doing that and see if it works