I've been struggling to fix an intermediate linking error that I get when using CMake to build my nvcc project. I've been upgrading a previous project to utilize CUDA and was able to successfully call functions from that library from host code. When I try to call functions of that library from device code, I get the intermediate linking error. I annotated all of the functions with __device__ and __host__ descriptors.
As a side note, this is a ROS project, so I'm using some of the catkin CMake functions.
This is a snippet from the ParticleFilter code that calls the host and device functions:
#include <cuda.h>
#include <cuda_runtime.h>
#include <device_launch_parameters.h>
#include <curand_kernel.h>
#include <iostream>
#include <davinci_kinematics_cuda/davinci_fwd_kinematics.cuh>
__host__
ParticleFilter::ParticleFilter(const unsigned int numParticles, const std::vector<double> &initialJointState, const unsigned int threads,
const unsigned int blocks) {
/* random other work here */
// This works fine (compiles and runs), it is calling host code from the other file
kinematics = davinci_kinematics_cuda::Forward();
std::cout << kinematics.fwd_kin_solve(initialJointState.data()).translation() << std::endl;
}
__global__
void printParticlesKernel(double *particles, const unsigned int numParticles, const unsigned int dimensions, const size_t pitch) {
int locationStart = blockIdx.x * blockDim.x + threadIdx.x;
int stride = blockDim.x * gridDim.x;
// This fails, will not link
davinci_kinematics_cuda::Forward kinematics = davinci_kinematics_cuda::Forward();
for (int n = locationStart; n < numParticles; n += stride) {
double *particle = (double*) ((char*) particles + n * pitch);
/* random other work here */
// this fails, will not link
auto translation = kinematics.fwd_kin_solve(particle).translation();
printf("%f %f %f\n", translation[0], translation[1], translation[2]);
}
}
And this is from the kinematics file:
#include <cuda.h>
#include <cuda_runtime.h>
#include <device_launch_parameters.h>
namespace davinci_kinematics_cuda {
// use member fncs to compute and multiply successive transforms
__host__ __device__
Forward::Forward() {
/* random initialization here */
}
__host__ __device__
Eigen::Affine3d Forward::fwd_kin_solve(const double *q_vec, const unsigned int desired_joint) {
/* other work here */
}
}
This is the relevant CMake parts for the ParticleFilter file.
cmake_minimum_required(VERSION 2.8.10)
project(tool_tracking LANGUAGES CUDA CXX)
# https://stackoverflow.com/questions/25748039/add-cuda-to-ros-package
find_package(CUDA REQUIRED)
# set CUDA_NVCC_FLAGS as you would do with CXX/C FLAGS
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CURAND_FLAGS} -fPIC")
set(CUDA_SEPARABLE_COMPILATION ON)
find_package(catkin REQUIRED COMPONENTS
message_generation
roscpp
std_msgs
sensor_msgs
geometry_msgs
cwru_opencv_common
tool_model
cwru_davinci_control
cwru_davinci_kinematics
xform_utils
tf
tool_segmentation
)
catkin_package(
INCLUDE_DIRS
include
LIBRARIES
tool_tracking_particle
CATKIN_DEPENDS
message_runtime
std_msgs
sensor_msgs
geometry_msgs
cwru_opencv_common
tool_model
cwru_davinci_control
cwru_davinci_kinematics
xform_utils
tf
)
include_directories(SYSTEM ${OpenCV_INCLUDE_DIRS})
include_directories(include ${catkin_INCLUDE_DIRS} tool_model_lib )
cuda_add_executable(test_particlefilter src/ParticleFilter.cu src/Particle.cu)
target_link_libraries(test_particlefilter tool_tracking_particle ${catkin_LIBRARIES} ${OpenCV_LIBRARIES} ${CUDA_LIBRARIES})
This is the error from CMake:
/usr/bin/cmake -H/home/ethan/catkin_ws/src/cwru_davinci_tool_tracking/tool_tracking -B/home/ethan/catkin_ws/build/tool_tracking --check-build-system CMakeFiles/Makefile.cmake 0
/usr/bin/cmake -E cmake_progress_start /home/ethan/catkin_ws/build/tool_tracking/CMakeFiles /home/ethan/catkin_ws/build/tool_tracking/CMakeFiles/progress.marks
/usr/bin/make -f CMakeFiles/Makefile2 all
make[1]: Entering directory '/home/ethan/catkin_ws/build/tool_tracking'
/usr/bin/make -f CMakeFiles/test_particlefilter.dir/build.make CMakeFiles/test_particlefilter.dir/depend
make[2]: Entering directory '/home/ethan/catkin_ws/build/tool_tracking'
[ 20%] Building NVCC intermediate link file CMakeFiles/test_particlefilter.dir/test_particlefilter_intermediate_link.o
/usr/local/cuda-11.0/bin/nvcc -lcudadevrt -m64 -ccbin /usr/bin/cc -dlink /home/ethan/catkin_ws/build/tool_tracking/CMakeFiles/test_particlefilter.dir/src/./test_particlefilter_generated_ParticleFilter.cu.o /home/ethan/catkin_ws/build/tool_tracking/CMakeFiles/test_particlefilter.dir/src/./test_particlefilter_generated_Particle.cu.o -o /home/ethan/catkin_ws/build/tool_tracking/CMakeFiles/test_particlefilter.dir/./test_particlefilter_intermediate_link.o -Xcompiler -fPIC
nvlink error : Undefined reference to '_ZN23davinci_kinematics_cuda7ForwardC1Ev' in '/home/ethan/catkin_ws/build/tool_tracking/CMakeFiles/test_particlefilter.dir/src/./test_particlefilter_generated_ParticleFilter.cu.o'
nvlink error : Undefined reference to '_ZN23davinci_kinematics_cuda7Forward13fwd_kin_solveEPKdj' in '/home/ethan/catkin_ws/build/tool_tracking/CMakeFiles/test_particlefilter.dir/src/./test_particlefilter_generated_ParticleFilter.cu.o'
CMakeFiles/test_particlefilter.dir/build.make:1468: recipe for target 'CMakeFiles/test_particlefilter.dir/test_particlefilter_intermediate_link.o' failed
make[2]: Leaving directory '/home/ethan/catkin_ws/build/tool_tracking'
make[2]: *** [CMakeFiles/test_particlefilter.dir/test_particlefilter_intermediate_link.o] Error 255
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/test_particlefilter.dir/all' failed
make[1]: Leaving directory '/home/ethan/catkin_ws/build/tool_tracking'
make[1]: *** [CMakeFiles/test_particlefilter.dir/all] Error 2
Makefile:140: recipe for target 'all' failed
make: *** [all] Error 2
How do I fix the error with the undefined reference? Seems like a linking error, but I am not familiar enough with the compilation / linking process to troubleshoot any further. If I need to post the CMake from the kinematics file I can as well.
Here's the key issue and the part that will be most helpful to other readers of this question. Catkin configures CMake to build shared libraries by default but CUDA separable compilation and nvlink only work with static libraries. You need to set your CUDA libraries (in your case, those in cwru_davinci_kinematics) to be static, always. You can do that by adding the STATIC keyword to the add_library call, as in:
add_library(my_cuda_lib STATIC source1.cu ...)
If you "link" to a shared library with CUDA in CMake, it will just ignore it. This is actually the documented behavior of nvcc. See here: https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/#libraries
The device linker has the ability to read the static host library formats (.a on Linux and Mac OS X, .lib on Windows). It ignores any dynamic (.so or .dll) libraries.
Another major lesson here is that setting CMake to an ancient version is bound to cause problems. While reproducing your issue, I was forced to build OpenCV 3 from source (it's not in Ubuntu 20.04 LTS) and there is no good way to override the search path for a particular package prior to version 3.12, which introduced CMP0074.
Upgrade your minimum CMake version. Ideally you would upgrade to the newest version available to you in your software repositories and set your files' minimums to that. There is zero benefit to being compatible with CMake versions earlier than ~3.5, and I would argue that extends up to 3.16 (the version in Ubuntu 20.04 LTS). Since you're using CUDA, 3.18 is most appropriate. Even worse, many of your projects set a minimum below 2.8.12; compatibility with this version will very soon be removed by CMake.
Here are the exact changes I made to get it to build on Ubuntu 20.04 LTS. I used the following build script, placed in and executed from the ROS workspace:
#!/usr/bin/bash
source /opt/ros/noetic/setup.bash
export CUDACXX=/usr/local/cuda/bin/nvcc
export OpenCV_ROOT=$(readlink -f opencv-install)
[ -f "$CUDACXX" ] || { echo "Invalid CUDACXX: $CUDACXX"; exit; }
[ -d "$OpenCV_ROOT" ] || { echo "Invalid OpenCV_ROOT: $OpenCV_ROOT"; exit; }
rm -rf build devel
catkin build tool_tracking --cmake-args \
-Wno-dev \
-DCMAKE_POLICY_DEFAULT_CMP0074=NEW \
-DCMAKE_CUDA_ARCHITECTURES=75
The directory opencv-install was created by building my own OpenCV 3 (because Ubuntu 20.04 only has v4). The steps for that were:
$ git clone -b 3.4.14 git#github.com:opencv/opencv.git
$ git clone -b 3.4.14 git#github.com:opencv/opencv_contrib.git
$ cmake -G Ninja -S opencv -B opencv-build/ -DOPENCV_EXTRA_MODULES_PATH=$(readlink -f opencv_contrib)/modules -DBUILD_opencv_cnn_3dobj=OFF -DBUILD_opencv_face=OFF -DBUILD_opencv_hdf=OFF -DBUILD_opencv_hfs=OFF -DBUILD_opencv_julia=OFF -DBUILD_opencv_matlab=OFF -DBUILD_opencv_ovis=OFF -DBUILD_opencv_reg=OFF -DBUILD_opencv_sfm=OFF -DBUILD_opencv_text=OFF -DBUILD_opencv_wechat_qrcode=OFF -DBUILD_opencv_ximgproc=OFF
$ cmake --build opencv-build
$ cmake --install opencv-build --prefix opencv-install
This disables the extra modules that have significant/irrelevant dependencies.
The script sets the environment variable OpenCV_ROOT to direct CMake to this locally installed version of OpenCV. Because the minimum version of CMake specified in the file is so low, I must also set CMAKE_POLICY_DEFAULT_CMP0074=NEW so that OpenCV_ROOT will be honored.
Here are the changes I made to your CMake code:
src/cwru_davinci_kinematics/CMakeLists.txt
--- a/src/cwru_davinci_kinematics/CMakeLists.txt
+++ b/src/cwru_davinci_kinematics/CMakeLists.txt
## -1,4 +1,4 ##
-cmake_minimum_required(VERSION 2.8.10)
+cmake_minimum_required(VERSION 3.18)
project(cwru_davinci_kinematics)
#This is needed as part of the migration to ros jade and later
## -26,18 +26,16 ## find_package(catkin REQUIRED COMPONENTS roscpp roslib roslint tf tf2 tf2_eigen)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=gnu++0x")
-# https://stackoverflow.com/questions/25748039/add-cuda-to-ros-package
-find_package(CUDA)
-message(STATUS "CUDA_FOUND=${CUDA_FOUND}")
-if(CUDA_FOUND)
- message(STATUS "Found CUDA, setting nvcc compilation flags")
-
- # set CUDA_NVCC_FLAGS as you would do with CXX/C FLAGS
- set(CUDA_NVCC_FLAGS CACHE STRING "nvcc flags" FORCE)
- set(CUDA_VERBOSE_BUILD ON CACHE BOOL "nvcc verbose" FORCE)
+include(CheckLanguage)
+check_language(CUDA)
+if (CMAKE_CUDA_COMPILER)
+ enable_language(CUDA)
+
# fPIC fixes some linker issues with nvcc code / objects
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CURAND_FLAGS} -fPIC")
- set(CUDA_SEPARABLE_COMPILATION ON)
+ set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -fPIC")
+ set(CMAKE_CUDA_SEPARABLE_COMPILATION ON)
+
+ find_package(CUDAToolkit REQUIRED)
endif()
include_directories(
## -48,7 +46,7 ## include_directories(
${YAML_CPP_INCLUDE_DIRS}
)
-if (CUDA_FOUND)
+if (CMAKE_CUDA_COMPILER)
catkin_package(
DEPENDS ${Eigen3_DEP}
LIBRARIES
## -82,14 +80,17 ## target_link_libraries(davinci_kinematics
davinci_kinematic_definitions
)
-if (CUDA_FOUND)
- cuda_add_library(davinci_kinematics_cuda src/davinci_fwd_kinematics.cu)
- cuda_add_library(davinci_kinematics_definitions_cuda src/davinci_kinematic_definitions.cu)
-
- target_link_libraries(davinci_kinematics_cuda
- ${catkin_LIBRARIES}
- davinci_kinematics_definitions_cuda
- )
+if (CMAKE_CUDA_COMPILER)
+ add_library(davinci_kinematics_cuda STATIC src/davinci_fwd_kinematics.cu)
+ add_library(davinci_kinematics_definitions_cuda STATIC src/davinci_kinematic_definitions.cu)
+
+ target_link_libraries(
+ davinci_kinematics_cuda
+ PRIVATE
+ CUDA::curand
+ ${catkin_LIBRARIES}
+ davinci_kinematics_definitions_cuda
+ )
endif()
# Examples
The important lines here are:
add_library(davinci_kinematics_cuda STATIC src/davinci_fwd_kinematics.cu)
add_library(davinci_kinematics_definitions_cuda STATIC src/davinci_kinematic_definitions.cu)
I also modernized the CMake code here, because the built-in CUDA language support has considerably advanced.
src/cwru_davinci_tool_tracking/tool_tracking/CMakeLists.txt
--- a/src/cwru_davinci_tool_tracking/tool_tracking/CMakeLists.txt
+++ b/src/cwru_davinci_tool_tracking/tool_tracking/CMakeLists.txt
## -1,18 +1,11 ##
-cmake_minimum_required(VERSION 2.8.10)
-project(tool_tracking LANGUAGES CUDA CXX)
+cmake_minimum_required(VERSION 3.18)
+project(tool_tracking LANGUAGES C CXX CUDA)
-# https://stackoverflow.com/questions/25748039/add-cuda-to-ros-package
-find_package(CUDA REQUIRED)
+set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -fPIC")
+set(CMAKE_CUDA_SEPARABLE_COMPILATION ON)
-# set CUDA_NVCC_FLAGS as you would do with CXX/C FLAGS
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CURAND_FLAGS} -fPIC")
-set(CUDA_SEPARABLE_COMPILATION ON)
+find_package(OpenCV 3 REQUIRED)
-#find_package(catkin_simple REQUIRED)
-## Find catkin macros and libraries
-## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
-## is used, also find other catkin packages
-find_package(OpenCV REQUIRED)
find_package(catkin REQUIRED COMPONENTS
message_generation
roscpp
## -28,11 +21,12 ## find_package(catkin REQUIRED COMPONENTS
tool_segmentation
)
+find_package(CUDAToolkit REQUIRED)
catkin_package(
INCLUDE_DIRS
include
- LIBRARIES
+ LIBRARIES
tool_tracking_particle
CATKIN_DEPENDS
message_runtime
## -47,13 +41,7 ## catkin_package(
tf
)
-include_directories(SYSTEM ${OpenCV_INCLUDE_DIRS})
-include_directories(include ${catkin_INCLUDE_DIRS} tool_model_lib )
-
-#cuda_add_library(tool_tracking_particle src/ParticleFilter.cu src/Particle.cu)
-#add_executable(particle src/tracking_particle.cpp)
-#target_link_libraries(particle tool_tracking_particle ${catkin_LIBRARIES} ${OpenCV_LIBRARIES} davinci_kinematics_cuda
-# davinci_kinematics_definitions_cuda)
-
-cuda_add_executable(test_particlefilter src/ParticleFilter.cu src/Particle.cu)
-target_link_libraries(test_particlefilter tool_tracking_particle ${catkin_LIBRARIES} ${OpenCV_LIBRARIES} ${CUDA_LIBRARIES})
+add_executable(test_particlefilter src/ParticleFilter.cu src/Particle.cu)
+target_include_directories(test_particlefilter SYSTEM PRIVATE ${OpenCV_INCLUDE_DIRS} ${catkin_INCLUDE_DIRS})
+target_include_directories(test_particlefilter PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
+target_link_libraries(test_particlefilter PRIVATE ${catkin_LIBRARIES} ${OpenCV_LIBRARIES} CUDA::curand)
I also modernized the CMake code here, because the built-in CUDA language support has considerably advanced.
Miscellaneous changes
I bumped the minimum CMake version from 2.8.x to 3.0.2 in all other places to suppress warnings. I also added a version number 3 to all find_package(OpenCV ...) calls that didn't have it.
Boost no longer has a python3 package; it's just python now. I made the following change to src/vision_opencv/cv_bridge/CMakeLists.txt:
--- a/src/vision_opencv/cv_bridge/CMakeLists.txt
+++ b/src/vision_opencv/cv_bridge/CMakeLists.txt
## -1,18 +1,15 ##
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 3.0.2)
project(cv_bridge)
find_package(catkin REQUIRED COMPONENTS rosconsole sensor_msgs)
if(NOT ANDROID)
find_package(PythonLibs)
- if(PYTHONLIBS_VERSION_STRING VERSION_LESS 3)
- find_package(Boost REQUIRED python)
- else()
- find_package(Boost REQUIRED python3)
- endif()
+ find_package(Boost REQUIRED python)
else()
-find_package(Boost REQUIRED)
+ find_package(Boost REQUIRED)
endif()
+
find_package(OpenCV 3 REQUIRED
COMPONENTS
opencv_core
Related
I'm building a small project that will output video. I'm trying to link to libswscale to convert RGBA to YUV420, however, the linker ld cannot successfully find libswscale symbols.
Undefined symbols for architecture x86_64:
"sws_getContext(int, int, AVPixelFormat, int, int, AVPixelFormat, int, SwsFilter*, SwsFilter*, double const*)", referenced from:
VideoWriter::writeFrame(std::__1::vector<char, std::__1::allocator<char> >) in video_writer.cpp.o
The offending line of code is this.
struct SwsContext *sws_ctx = sws_getContext(
avCodecContext->width, avCodecContext->height, AV_PIX_FMT_RGBA,
avCodecContext->width, avCodecContext->height, AV_PIX_FMT_YUV420P,
SWS_BILINEAR, NULL, NULL, NULL);
When I use -v on clang I see that the libswscale.dylib is being passed to ld. The dylib exists on the file system and is the same version as the library's header, as verified by otool.
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" -demangle -lto_library /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libLTO.dylib -no_deduplicate -dynamic -arch x86_64 -platform_version macos 10.15.0 11.1 -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk -o bin/main -search_paths_first -headerpad_max_install_names CMakeFiles/main.dir/src/main.cpp.o CMakeFiles/main.dir/src/window.cpp.o CMakeFiles/main.dir/src/video_writer.cpp.o -rpath /usr/local/lib /usr/local/lib/libGLEW.2.2.0.dylib /usr/local/lib/libboost_program_options-mt.dylib -framework OpenGL /usr/local/Cellar/sdl2_image/2.6.2/lib/libSDL2_image.dylib /usr/local/lib/libSDL2.dylib /usr/local/Cellar/ffmpeg/5.1.2/lib/libavcodec.dylib /usr/local/Cellar/ffmpeg/5.1.2/lib/libswscale.dylib /usr/local/Cellar/ffmpeg/5.1.2/lib/libavutil.dylib -lc++ -lSystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/12.0.0/lib/darwin/libclang_rt.osx.a -F/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/System/Library/Frameworks
This is my cmake file.
cmake_minimum_required(VERSION 3.19.2)
project(FragTool VERSION 1.0)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
# --- c++ build settings --- #
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weffc++ -O0")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_BUILD_TYPE Debug)
# --- dependencies --- #
find_package(GLEW REQUIRED)
find_package(Boost 1.79.0 COMPONENTS program_options REQUIRED)
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBAV REQUIRED IMPORTED_TARGET
libavcodec
libswscale
libavutil
)
pkg_check_modules(LIBSDL2 REQUIRED IMPORTED_TARGET
sdl2
sdl2_image
)
set(EXECUTABLE main)
add_executable(${EXECUTABLE} src/main.cpp)
target_sources(${EXECUTABLE} PRIVATE
${CMAKE_SOURCE_DIR}/src/window.cpp
${CMAKE_SOURCE_DIR}/src/video_writer.cpp
)
target_include_directories(${EXECUTABLE} PRIVATE ${CMAKE_SOURCE_DIR}/src)
target_include_directories(${EXECUTABLE} PRIVATE ${GLEW_INCLUDE_DIRS})
target_link_libraries(${EXECUTABLE} PRIVATE GLEW::glew)
target_link_libraries(${EXECUTABLE} PRIVATE ${Boost_LIBRARIES})
target_link_libraries(${EXECUTABLE} PRIVATE PkgConfig::LIBSDL2)
target_link_libraries(${EXECUTABLE} PRIVATE PkgConfig::LIBAV)
I'm stumped as to what could be causing the linker to fail, given that it is being passed the libswscale dylib correctly as far as I can tell. I checked for any other versions of the dylib on the system that maybe are shadowing it, but didn't see any.
I figured this out. It was because the include statement needed to be wrapped with extern "C".
extern "C"
{
#include <libswscale/swscale.h>
}
This question already has answers here:
Libraries in /usr/local/lib not found
(1 answer)
Why the installed program has error when loading shared library in linux (cmake)
(3 answers)
Closed 2 years ago.
I'm building a kmeans executable from this cmake file:
# check the minimum version
cmake_minimum_required( VERSION 3.16 )
# the project name
project( kmeans )
#########################################################################
#### Define all the global variables to compile the application
#########################################################################
set( APPLICATION_NAME "kmeans")
#########################################################################
#### Adjust compiling option for this application
#########################################################################
# force the Release build if not already set
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif(NOT CMAKE_BUILD_TYPE)
# setting common c++ flags
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp -pthread -std=c++17 -static-libgcc -DKMEANS_DATASET_PATH=\"\\\"${CMAKE_CURRENT_SOURCE_DIR}/dataset/\\\"\"")
# setting debug flags
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -g3 -O0")
# setting release with debug info flags
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -march=native -mtune=native -g3 -O2")
# setting release flags
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -march=native -mtune=native -O3")
#########################################################################
#### Find external libaries
#########################################################################
# Boost program options
find_package(Boost REQUIRED program_options)
# include the directories
include_directories(${Boost_INCLUDES} )
################################
#### Sources
################################
set( KMEANS_SRC_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src)
set( KMEANS_HDR_PATH ${CMAKE_CURRENT_SOURCE_DIR}/include)
set( KMEANS_HDR_FILES
${KMEANS_HDR_PATH}/kmeans.h
)
set( KMEANS_SRC_FILES
${KMEANS_SRC_PATH}/main.cc
${KMEANS_SRC_PATH}/cluster.c
${KMEANS_SRC_PATH}/kmeans_clustering.c
)
include_directories( ${KMEANS_HDR_PATH} )
################################
#### Compilation
################################
#----- Set binary name for the mini-app
add_executable(${APPLICATION_NAME} ${KMEANS_SRC_FILES} ${KMEANS_HDR_FILES})
target_link_libraries(${APPLICATION_NAME} Boost::program_options)
################################
#### Install
################################
install( TARGETS ${APPLICATION_NAME} DESTINATION ${PROJECT_SOURCE_DIR}/bin )
After building the kmeans executable gets generated correctly inside the build dir (build/kmeans) and works perfectly. After a make install tho the generated binary (bin/kmeans) gives the following error ./kmeans: error while loading shared libraries: libboost_program_options.so.1.75.0: cannot open shared object file: No such file or directory. I tried to take a look at the install command doc but couldn't find any option taking care of the case. I suppose I'm missing something inside the cmake file but cannot spot it.
Background
I am trying to build a custom software inside Yocto build. Software is built by CMake.
The following is my recipe - customsoftware.bb:
SRCBRANCH = "master"
SRCREV = "master"
MY_SRC = "OMITTED"
SRC_URI = "${MY_SRC};branch=${SRCBRANCH}"
# libraries dependencies
DEPENDS += "boost"
S = "${WORKDIR}/git"
B = "${WORKDIR}/build"
PARALLEL_MAKE ?= "-j 1"
inherit cmake
# My CMake Options
EXTRA_OECMAKE+=" -DSOME_OPTION=ON"
# I want unix makefiles instead on ninja build
OECMAKE_GENERATOR="Unix Makefiles"
The following is a watered down version of my cmake project - CMakeLists.txt
Please note: I have omitted irrelevant parts for brevity
cmake_minimum_required(VERSION 3.0.0)
#---------------------------------------------------------------------------------------
# set default build to release
#---------------------------------------------------------------------------------------
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose Release or Debug" FORCE)
endif()
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/dist/)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/dist/bin)
set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
set(CMAKE_DISABLE_SOURCE_CHANGES ON)
if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
message(FATAL_ERROR "
${BoldRed}Error:${ColourReset} In-source builds are not allowed. You should create separate directory for build files.
${Magenta}CMAKE_BINARY_DIR${ColourReset}(${CMAKE_SOURCE_DIR}) must be different from ${Magenta}CMAKE_SOURCE_DIR${ColourReset}(${CMAKE_BINARY_DIR})
")
endif ()
project(myapp)
find_package(Boost REQUIRED COMPONENTS thread)
add_executable(${PROJECT_NAME}
${HEADERS}
${SOURCES}
)
target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES})
#Copy entire contents of dist/ to /opt/myapp
install(DIRECTORY ${CMAKE_BINARY_DIR}/dist/
DESTINATION /opt/myapp
)
I have appended my recipe to image.
Issue
When I ran du -h tmp/work/.../<customsoftware>/build/dist/bin binary size is 80MB. Also, after deploying to target system binary size is 80MB.
UPDATE
As suggested in comments, binaries at tmp/work/.../<customsoftware>/image are not stripped. However, binaries at tmp/work/.../<customsoftware>/packages-split are stripped.
If I ran make in source of app - not through recipe and outside yocto - binary size is 1.7MB
Question
If I remember correctly, OE build will strip debug symbols from resulting binaries.
Why does my binary still get deployed with debug symbols? What have I missed?
How can I make sure only stripped - Release type - binary is deployed?
Explicitly specifying package types and inheriting pkgconfig solved my issue. Updated recipe:
SRCBRANCH = "master"
SRCREV = "master"
MY_SRC = "OMITTED"
SRC_URI = "${MY_SRC};branch=${SRCBRANCH}"
DEPENDS += "boost"
S = "${WORKDIR}/git"
PARALLEL_MAKE ?= "-j 1"
inherit pkgconfig cmake
EXTRA_OECMAKE+=" -DSOME_OPTION"
OECMAKE_GENERATOR="Unix Makefiles"
# Specify package types
PACKAGES = "${PN}-dbg ${PN}"
FILES_${PN}-dbg += "\
<INSTALL_PATH>/.debug \
"
FILES_${PN} += "\
<INSTALL_PATH>/* \
"
Can you please try to see if this simple Hello World is stripped or not in your environment?
recipe:
DESCRIPTION = "Simple helloworld cmake"
LICENSE = "MIT"
SECTION = "examples"
LIC_FILES_CHKSUM =
"file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
SRC_URI = "file://CMakeLists.txt \
file://helloworld.c"
S = "${WORKDIR}"
inherit cmake
EXTRA_OECMAKE = ""
CMakeLists.txt:
cmake_minimum_required(VERSION 2.8.10)
project(helloworld)
add_executable(helloworld helloworld.c)
install(TARGETS helloworld RUNTIME DESTINATION bin)
helloworld.c:
#include <stdio.h>
int main() {
printf("Hello World Makefile from CMake!\n");
return(0);
}
if you don't mind about debug version
you can do
OECMAKE_C_FLAGS_RELEASE += "-s"
OECMAKE_CXX_FLAGS_RELEASE += "-s"
It will strip your binaries
How can I get CMake to link pthread statically on Windows? I use MSYS2 MinGW 32 bit and cmake v3.7.
What I would like to achieve is a compiler invocation like
g++ -static-libgcc -static-libstdc++ -std=c++11 -o test test.cpp -Wl,-Bstatic -lpthread
Setting
target_link_libraries(test PUBLIC "-Wl,-Bstatic -lpthread")
results in -Wl,-Bdynamic -Wl,-Bstatic -lpthread being called. If I change CMAKE_EXE_LINKER_FLAGS, pthreads is included before my object files and thus symbols are not resolved.
find the Threads module:
find_package(Threads REQUIRED)
add_executable(myApp main.cpp)
target_link_libraries(myApp Threads::Threads)
Note from the documentation:
For systems with multiple thread libraries, caller can set CMAKE_THREAD_PREFER_PTHREAD
As the FindThreads.cmake mention in its source code:
# For systems with multiple thread libraries, caller can set
#
# ::
#
# CMAKE_THREAD_PREFER_PTHREAD
#
# If the use of the -pthread compiler and linker flag is preferred then the
# caller can set
#
# ::
#
# THREADS_PREFER_PTHREAD_FLAG
#
# Please note that the compiler flag can only be used with the imported
# target. Use of both the imported target as well as this switch is highly
# recommended for new code.
So in addition to what already said, you might need to set the additional flag THREADS_PREFER_PTHREAD_FLAG. In some systems (OSX, etc.) this flag is needed at compilation time because it defines some macros that would be missing if you would only link -lpthread.
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
add_library(test test.cpp)
set_property(TARGET test PROPERTY CXX_STANDARD 11)
set_target_properties(test PROPERTIES LINK_SEARCH_START_STATIC 1)
set_target_properties(test PROPERTIES LINK_SEARCH_END_STATIC 1)
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++")
find_package(Threads REQUIRED)
target_link_libraries(test Threads::Threads)
Does it help?
cmake version 2.8.5
I am trying to compile my project using cmake. However, when i compile I don't think I am including the debug cflags i.e. -ggdb -D_DEBUG. As when I try and debug there is no debub info.
Is there any problem with the CMakeLists.txt files. I have 3 of them
# Mimimum version of cmake required
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
# Name of project
PROJECT(sdp_creator C)
# Check for correct compiler
# Using C compiler GNUCXX for c++ compiler
IF(CMAKE_COMPILER_IS_GNUCC)
MESSAGE(STATUS "=== GCC C COMPILER DETECTED")
SET(CMAKE_C_FLAGS "-m32 -ggdb -D_DEBUG -Wextra -Wall -Wunreachable-code -O0 -D_LARGEFILE64_SOURCE")
ENDIF(CMAKE_COMPILER_IS_GNUCC)
# Using windows compiler i.e. msvc++
IF(WIN32)
MESSAGE(STATUS "=== MSVC COMPILER DETECTED")
ENDIF(WIN32)
# Location of directory where include files are kept
INCLUDE_DIRECTORIES($ENV{HOME}/projects/sdp_creator/src/sdp)
INCLUDE_DIRECTORIES($ENV{HOME}/projects/sdp_creator/src/apr/inc)
# Location of directory where libraries are kept
LINK_DIRECTORIES($ENV{HOME}/projects/sdp_creator/src/apr/lib)
# Add subdirectories
ADD_SUBDIRECTORY(driver)
ADD_SUBDIRECTORY(sdp)
building shared library:
# Create a shared library called libsdp from sdp.c
# NOTE: static is the default
# NOTE: the lib prefix is automatically added
ADD_LIBRARY(sdp SHARED sdp.c)
Creating executable:
# Add executable called sdp_creator from source file
ADD_EXECUTABLE(sdp_creator main.c)
# Link the sdp library and other libraries with the excutable
#if using windows compiler add additional windows libraries
IF(WIN32)
TARGET_LINK_LIBRARIES(sdp_creator libsdp ws2_32)
MESSAGE(STATUS "=== Linking executable with windows libraries")
ENDIF(WIN32)
# if using gcc compiler
# NOTE: no need to add the -l prefix i.e. -lsdp, no automatically
IF(CMAKE_COMPILER_IS_GNUCC)
TARGET_LINK_LIBRARIES(sdp_creator sdp apr-1)
MESSAGE(STATUS "=== Linking executable with posix libraries")
ENDIF(CMAKE_COMPILER_IS_GNUCC)
Many thanks for any advice,
If you're using the "Unix Makefiles" (or any Makefile-based) generator, set the variable CMAKE_BUILD_TYPE to "Debug"
cmake -DCMAKE_BUILD_TYPE=Debug ../src
That will automatically add the right definitions and flags for your compiler. You should not have to add any flags yourself.
With multi-configuration generators, (like Visual Studio and Xcode), CMAKE_BUILD_TYPE is ignored, because the choice of whether to build a Debug or Release configuration is left up to the developer at build-time, and is not known at CMake configure time.
You can check the exact steps used in make by setting VERBOSE=1. That will tell you if the flags were included or not.
cmake project_dir
make VERBOSE=1
You can also check the CMakeCache.txt to see what value is assigned to CMAKE_C_FLAGS variable.
you can use the CMAKE_C_FLAGS and CMAKE_CXX_FLAGS flags with -g0/1/2 (debug information flag for the compiler. -g2 is the highest information):
cmake ... -DCMAKE_C_FLAGS="-g2" -DCMAKE_CXX_FLAGS="-g2" ...
Another option, if unix Makefiles are used to build the project, is to set CMAKE_BUILD_TYPE in CMakeLists.txt file directly:
set(CMAKE_BUILD_TYPE Debug)
You can find more in
$ man cmakevars
Look for CMAKE_BUILD_TYPE