未定义的引用,因为我找不到相应的源文件
undefined reference because I can't find the according source files
我有一个程序中的 cpp 文件,我想将其与整个文件结构分开打开。我需要这样做才能在 ros 中使用这个 cpp 文件。我包含了 header 文件,但如果我是正确的,我还需要包含源文件。
我的 cpp 文件名为 open_camera.cpp 并包含一个 header 文件 /usr/include/ids_peak-1.3.0/peak/backend/peak_backend.h
peak_backend.h 文件包含这样的声明:
PEAK_C_API PEAK_Library_GetLastError(
PEAK_RETURN_CODE* lastErrorCode, char* lastErrorDescription, size_t* lastErrorDescriptionSize);
我的 Cmake 文件如下所示:
cmake_minimum_required(VERSION 3.0.2)
project(ros_package)
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
)
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES ros_package
# CATKIN_DEPENDS roscpp rospy std_msgs
# DEPENDS system_lib
)
###########
## Build ##
###########
## Specify additional locations of header files
## Your package locations should be listed before other locations
include_directories(
# include
${catkin_INCLUDE_DIRS}
)
add_executable(open_camera_node src/open_camera.cpp)
#############
## Install ##
#############
include_directories(/usr/include/ids_peak-1.3.0)
如果我 运行 catkin_make 我得到如下错误:
/usr/bin/ld: CMakeFiles/open_camera_node.dir/src/open_camera.cpp.o: in function `void peak::core::ExecuteAndMapReturnCodes<(anonymous namespace)::CallAndCheckCInterfaceFunction(std::function<int ()> const&)::{lambda()#1}>((anonymous namespace)::CallAndCheckCInterfaceFunction(std::function<int ()> const&)::{lambda()#1} const&)':
open_camera.cpp:(.text+0x516): undefined reference to `PEAK_Library_GetLastError'
据我了解,问题是我需要 link header 的源文件。我该怎么做,我在哪里可以找到我的 header 的源文件?我找了一段时间没找到
open_camera.cpp 有自己的 CMake 文件,如下所示:
cmake_minimum_required(VERSION 3.2 FATAL_ERROR)
project ("open_camera_cpp")
message (STATUS "[${PROJECT_NAME}] Processing ${CMAKE_CURRENT_LIST_FILE}")
set (SAMPLE_TARGET_NAME ${PROJECT_NAME})
set (CMAKE_SCRIPTS_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../_cmake_scripts" CACHE STRING "The path of the cmake scripts directory.")
set (SAMPLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/output/bin")
include (${CMAKE_SCRIPTS_PATH}/cmake_detect_architecture.cmake)
detect_target_architecture (ARCH)
add_executable (${SAMPLE_TARGET_NAME}
open_camera.cpp
)
set (LIBRARY_NAME_VISION_API "ids_peak")
string (TOUPPER ${LIBRARY_NAME_VISION_API} LIBRARY_NAME_UPPER_VISION_API)
if (NOT TARGET ids_peak)
file (TO_CMAKE_PATH "$ENV{IDS_PEAK_SDK_PATH}/api" ${LIBRARY_NAME_UPPER_VISION_API}_PACKAGE_DIR)
set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${${LIBRARY_NAME_UPPER_VISION_API}_PACKAGE_DIR}/cmake_finder")
message (STATUS "[${PROJECT_NAME}] Will find IDS peak API library.. CMAKE_MODULE_PATH: ${CMAKE_MODULE_PATH}")
find_package (ids_peak REQUIRED)
endif ()
target_include_directories (${SAMPLE_TARGET_NAME}
PRIVATE ${${LIBRARY_NAME_UPPER_VISION_API}_INCLUDE_DIR}
)
find_package (Threads REQUIRED)
target_link_libraries (${SAMPLE_TARGET_NAME}
ids_peak
${CMAKE_THREAD_LIBS_INIT}
)
if ((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
target_link_libraries (${SAMPLE_TARGET_NAME}
atomic
)
endif ()
# Set output directories for all configuration types (Debug, Release, etc.)
if (NOT CMAKE_BUILD_TYPE)
set (CMAKE_BUILD_TYPE "Debug")
endif()
if (NOT CMAKE_CONFIGURATION_TYPES)
set (CMAKE_CONFIGURATION_TYPES ${CMAKE_BUILD_TYPE})
endif ()
if (CMAKE_CONFIGURATION_TYPES)
foreach (CONFIGURATION_TYPE ${CMAKE_CONFIGURATION_TYPES})
string (TOUPPER ${CONFIGURATION_TYPE} CONFIGURATION_TYPE_UPPER)
if (CONFIGURATION_TYPE_UPPER STREQUAL "RELEASE")
set (SAMPLE_RUNTIME_OUTPUT_NAME ${SAMPLE_TARGET_NAME})
set (SAMPLE_RUNTIME_OUTPUT_DIRECTORY ${SAMPLE_OUTPUT_PATH}/${ARCH})
else ()
string (TOLOWER ${CONFIGURATION_TYPE} CONFIGURATION_TYPE_LOWER)
set (SAMPLE_RUNTIME_OUTPUT_NAME "${SAMPLE_TARGET_NAME}_${CONFIGURATION_TYPE_LOWER}")
set (SAMPLE_RUNTIME_OUTPUT_DIRECTORY ${SAMPLE_OUTPUT_PATH}/${ARCH}/${CONFIGURATION_TYPE})
endif ()
set_target_properties (${SAMPLE_TARGET_NAME} PROPERTIES
RUNTIME_OUTPUT_NAME_${CONFIGURATION_TYPE_UPPER} ${SAMPLE_RUNTIME_OUTPUT_NAME}
RUNTIME_OUTPUT_DIRECTORY_${CONFIGURATION_TYPE_UPPER} ${SAMPLE_RUNTIME_OUTPUT_DIRECTORY}
)
message (STATUS "[${PROJECT_NAME}] Cfg ${CONFIGURATION_TYPE} -> Output directory: ${SAMPLE_RUNTIME_OUTPUT_DIRECTORY}, Output name: ${SAMPLE_RUNTIME_OUTPUT_NAME}")
endforeach ()
endif ()
set_target_properties(${SAMPLE_TARGET_NAME} PROPERTIES
CXX_STANDARD 14
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS NO
)
if (MSVC)
target_compile_options (${SAMPLE_TARGET_NAME}
PRIVATE "/bigobj"
PRIVATE "/MP"
)
endif ()
GET_PROPERTY(${LIBRARY_NAME_UPPER_VISION_API}_LIBRARIES_COPIED_LOCAL GLOBAL PROPERTY ${LIBRARY_NAME_UPPER_VISION_API}_LIBRARIES_COPIED)
if(NOT ${LIBRARY_NAME_UPPER_VISION_API}_LIBRARIES_COPIED_LOCAL)
file (GLOB ids_peak_LIBS
"${${LIBRARY_NAME_UPPER_VISION_API}_LIBRARY_DIR}/*${CMAKE_SHARED_LIBRARY_SUFFIX}"
)
foreach (ids_peak_LIBRARY ${ids_peak_LIBS})
message (STATUS "[${PROJECT_NAME}] Add PostBuildStep for copy of ${ids_peak_LIBRARY}.")
add_custom_command (TARGET ${SAMPLE_TARGET_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${ids_peak_LIBRARY}
$<TARGET_FILE_DIR:${SAMPLE_TARGET_NAME}>
COMMENT "Post build copy of ${ids_peak_LIBRARY} to output dir." VERBATIM
)
endforeach ()
SET_PROPERTY(GLOBAL PROPERTY ${LIBRARY_NAME_UPPER_VISION_API}_LIBRARIES_COPIED ON)
endif()
# For Unix Build we need the environment variable GENICAM_GENTL32_PATH respectivily GENICAM_GENTL64_PATH to find the GenTL producer libraries.
# To set these environment variables a shell script is used which can be found in the samples root folder in _cmake_scripts.
# To run the samples run this script not the binary.
if (UNIX)
string (TOLOWER ${CMAKE_BUILD_TYPE} CONFIGURATION_TYPE_LOWER)
if(${CONFIGURATION_TYPE_LOWER} STREQUAL "release")
set(VSSL_SAMPLE_BINARY_NAME ${PROJECT_NAME})
else()
set(VSSL_SAMPLE_BINARY_NAME ${PROJECT_NAME}_${CONFIGURATION_TYPE_LOWER})
endif()
configure_file(${CMAKE_SCRIPTS_PATH}/sample_starter.in ${CMAKE_CURRENT_BINARY_DIR}/${VSSL_SAMPLE_BINARY_NAME}.sh)
file(COPY ${CMAKE_CURRENT_BINARY_DIR}/${VSSL_SAMPLE_BINARY_NAME}.sh
DESTINATION ${SAMPLE_RUNTIME_OUTPUT_DIRECTORY}
FILE_PERMISSIONS
OWNER_READ OWNER_WRITE OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE
WORLD_READ WORLD_EXECUTE
)
endif (UNIX)
我不太了解原始 cmake 文件,因为我对这个话题还很陌生。
cpp文件路径为:/usr/local/src/ids/samples/peak/cpp/open_camera/open_camera.cpp
根据 CMake 文档,我们不应再对包含目录等使用全局设置,而应使用 target_
版本。老实说,我不认为第二个复杂的 CMakeLists.txt 被使用(或需要),它似乎不包含在第一个中(但如果不知道目录结构。
但是,无论如何,如果你想使用一些库,你需要两样东西:带有所提供项目声明的头文件和通常包含 definition/implementation 的已编译库项目(静态或动态库)。原则上,如果您可以访问库源文件,您也可以自己编译库。在这种情况下,我的建议是:
add_library(ids_peak
${IDS_PEAK_SOURCE_FILES}
)
target_include_directories(ids_peak PUBLIC /usr/include/ids_peak-1.3.0)
...
add_executable(open_camera
src/open_camera.cpp
)
target_include_directories(open_camera PRIVATE ${catkin_INCLUDE_DIRS})
target_link_libraries(open_camera PRIVATE ids_peak)
这将定义两个要编译的目标:
- 一个库目标,编译列表 ${ID_PEAK_SOURCE_FILES} 中的任何源文件并附加相应的包含目录
- 一个可执行目标,正在编译您的 open_camera.cpp 源文件。附有这个 catkin 包含目录(也许我们应该在这里选择其他库目标?是否有编译源或是否只有 lib+headers?)。最后但并非最不重要的是,向该目标添加了一个依赖项。
由于库目标的包含目录被声明为 public,它们被转发到依赖于它的所有目标(target_compile_definitions
、target_link_libraries
、target_link_options
, 等等).
您可能会对这些链接感兴趣:
- https://cmake.org/cmake/help/latest/command/add_library.html
- https://cmake.org/cmake/help/latest/command/add_executable.html
- https://cmake.org/cmake/help/latest/command/target_include_directories.html
- https://cmake.org/cmake/help/latest/command/target_link_libraries.html
- What do linkers do?
而且,如果您愿意挂断 FILE(GLOB...)
电话。有一次,一些 CMake 贡献者告诉我,这个功能没有发布,但是被逃脱了,根本不应该使用,因为它很容易出错。我知道它会派上用场,但您无法真正控制您的构建真正在做什么。最好明确命名文件。或者,在安装 (https://cmake.org/cmake/help/latest/command/install.html#directory) 或复制的情况下,您可以应用到整个目录。
我有一个程序中的 cpp 文件,我想将其与整个文件结构分开打开。我需要这样做才能在 ros 中使用这个 cpp 文件。我包含了 header 文件,但如果我是正确的,我还需要包含源文件。
我的 cpp 文件名为 open_camera.cpp 并包含一个 header 文件 /usr/include/ids_peak-1.3.0/peak/backend/peak_backend.h
peak_backend.h 文件包含这样的声明:
PEAK_C_API PEAK_Library_GetLastError(
PEAK_RETURN_CODE* lastErrorCode, char* lastErrorDescription, size_t* lastErrorDescriptionSize);
我的 Cmake 文件如下所示:
cmake_minimum_required(VERSION 3.0.2)
project(ros_package)
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
)
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES ros_package
# CATKIN_DEPENDS roscpp rospy std_msgs
# DEPENDS system_lib
)
###########
## Build ##
###########
## Specify additional locations of header files
## Your package locations should be listed before other locations
include_directories(
# include
${catkin_INCLUDE_DIRS}
)
add_executable(open_camera_node src/open_camera.cpp)
#############
## Install ##
#############
include_directories(/usr/include/ids_peak-1.3.0)
如果我 运行 catkin_make 我得到如下错误:
/usr/bin/ld: CMakeFiles/open_camera_node.dir/src/open_camera.cpp.o: in function `void peak::core::ExecuteAndMapReturnCodes<(anonymous namespace)::CallAndCheckCInterfaceFunction(std::function<int ()> const&)::{lambda()#1}>((anonymous namespace)::CallAndCheckCInterfaceFunction(std::function<int ()> const&)::{lambda()#1} const&)':
open_camera.cpp:(.text+0x516): undefined reference to `PEAK_Library_GetLastError'
据我了解,问题是我需要 link header 的源文件。我该怎么做,我在哪里可以找到我的 header 的源文件?我找了一段时间没找到
open_camera.cpp 有自己的 CMake 文件,如下所示:
cmake_minimum_required(VERSION 3.2 FATAL_ERROR)
project ("open_camera_cpp")
message (STATUS "[${PROJECT_NAME}] Processing ${CMAKE_CURRENT_LIST_FILE}")
set (SAMPLE_TARGET_NAME ${PROJECT_NAME})
set (CMAKE_SCRIPTS_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../_cmake_scripts" CACHE STRING "The path of the cmake scripts directory.")
set (SAMPLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/output/bin")
include (${CMAKE_SCRIPTS_PATH}/cmake_detect_architecture.cmake)
detect_target_architecture (ARCH)
add_executable (${SAMPLE_TARGET_NAME}
open_camera.cpp
)
set (LIBRARY_NAME_VISION_API "ids_peak")
string (TOUPPER ${LIBRARY_NAME_VISION_API} LIBRARY_NAME_UPPER_VISION_API)
if (NOT TARGET ids_peak)
file (TO_CMAKE_PATH "$ENV{IDS_PEAK_SDK_PATH}/api" ${LIBRARY_NAME_UPPER_VISION_API}_PACKAGE_DIR)
set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${${LIBRARY_NAME_UPPER_VISION_API}_PACKAGE_DIR}/cmake_finder")
message (STATUS "[${PROJECT_NAME}] Will find IDS peak API library.. CMAKE_MODULE_PATH: ${CMAKE_MODULE_PATH}")
find_package (ids_peak REQUIRED)
endif ()
target_include_directories (${SAMPLE_TARGET_NAME}
PRIVATE ${${LIBRARY_NAME_UPPER_VISION_API}_INCLUDE_DIR}
)
find_package (Threads REQUIRED)
target_link_libraries (${SAMPLE_TARGET_NAME}
ids_peak
${CMAKE_THREAD_LIBS_INIT}
)
if ((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
target_link_libraries (${SAMPLE_TARGET_NAME}
atomic
)
endif ()
# Set output directories for all configuration types (Debug, Release, etc.)
if (NOT CMAKE_BUILD_TYPE)
set (CMAKE_BUILD_TYPE "Debug")
endif()
if (NOT CMAKE_CONFIGURATION_TYPES)
set (CMAKE_CONFIGURATION_TYPES ${CMAKE_BUILD_TYPE})
endif ()
if (CMAKE_CONFIGURATION_TYPES)
foreach (CONFIGURATION_TYPE ${CMAKE_CONFIGURATION_TYPES})
string (TOUPPER ${CONFIGURATION_TYPE} CONFIGURATION_TYPE_UPPER)
if (CONFIGURATION_TYPE_UPPER STREQUAL "RELEASE")
set (SAMPLE_RUNTIME_OUTPUT_NAME ${SAMPLE_TARGET_NAME})
set (SAMPLE_RUNTIME_OUTPUT_DIRECTORY ${SAMPLE_OUTPUT_PATH}/${ARCH})
else ()
string (TOLOWER ${CONFIGURATION_TYPE} CONFIGURATION_TYPE_LOWER)
set (SAMPLE_RUNTIME_OUTPUT_NAME "${SAMPLE_TARGET_NAME}_${CONFIGURATION_TYPE_LOWER}")
set (SAMPLE_RUNTIME_OUTPUT_DIRECTORY ${SAMPLE_OUTPUT_PATH}/${ARCH}/${CONFIGURATION_TYPE})
endif ()
set_target_properties (${SAMPLE_TARGET_NAME} PROPERTIES
RUNTIME_OUTPUT_NAME_${CONFIGURATION_TYPE_UPPER} ${SAMPLE_RUNTIME_OUTPUT_NAME}
RUNTIME_OUTPUT_DIRECTORY_${CONFIGURATION_TYPE_UPPER} ${SAMPLE_RUNTIME_OUTPUT_DIRECTORY}
)
message (STATUS "[${PROJECT_NAME}] Cfg ${CONFIGURATION_TYPE} -> Output directory: ${SAMPLE_RUNTIME_OUTPUT_DIRECTORY}, Output name: ${SAMPLE_RUNTIME_OUTPUT_NAME}")
endforeach ()
endif ()
set_target_properties(${SAMPLE_TARGET_NAME} PROPERTIES
CXX_STANDARD 14
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS NO
)
if (MSVC)
target_compile_options (${SAMPLE_TARGET_NAME}
PRIVATE "/bigobj"
PRIVATE "/MP"
)
endif ()
GET_PROPERTY(${LIBRARY_NAME_UPPER_VISION_API}_LIBRARIES_COPIED_LOCAL GLOBAL PROPERTY ${LIBRARY_NAME_UPPER_VISION_API}_LIBRARIES_COPIED)
if(NOT ${LIBRARY_NAME_UPPER_VISION_API}_LIBRARIES_COPIED_LOCAL)
file (GLOB ids_peak_LIBS
"${${LIBRARY_NAME_UPPER_VISION_API}_LIBRARY_DIR}/*${CMAKE_SHARED_LIBRARY_SUFFIX}"
)
foreach (ids_peak_LIBRARY ${ids_peak_LIBS})
message (STATUS "[${PROJECT_NAME}] Add PostBuildStep for copy of ${ids_peak_LIBRARY}.")
add_custom_command (TARGET ${SAMPLE_TARGET_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${ids_peak_LIBRARY}
$<TARGET_FILE_DIR:${SAMPLE_TARGET_NAME}>
COMMENT "Post build copy of ${ids_peak_LIBRARY} to output dir." VERBATIM
)
endforeach ()
SET_PROPERTY(GLOBAL PROPERTY ${LIBRARY_NAME_UPPER_VISION_API}_LIBRARIES_COPIED ON)
endif()
# For Unix Build we need the environment variable GENICAM_GENTL32_PATH respectivily GENICAM_GENTL64_PATH to find the GenTL producer libraries.
# To set these environment variables a shell script is used which can be found in the samples root folder in _cmake_scripts.
# To run the samples run this script not the binary.
if (UNIX)
string (TOLOWER ${CMAKE_BUILD_TYPE} CONFIGURATION_TYPE_LOWER)
if(${CONFIGURATION_TYPE_LOWER} STREQUAL "release")
set(VSSL_SAMPLE_BINARY_NAME ${PROJECT_NAME})
else()
set(VSSL_SAMPLE_BINARY_NAME ${PROJECT_NAME}_${CONFIGURATION_TYPE_LOWER})
endif()
configure_file(${CMAKE_SCRIPTS_PATH}/sample_starter.in ${CMAKE_CURRENT_BINARY_DIR}/${VSSL_SAMPLE_BINARY_NAME}.sh)
file(COPY ${CMAKE_CURRENT_BINARY_DIR}/${VSSL_SAMPLE_BINARY_NAME}.sh
DESTINATION ${SAMPLE_RUNTIME_OUTPUT_DIRECTORY}
FILE_PERMISSIONS
OWNER_READ OWNER_WRITE OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE
WORLD_READ WORLD_EXECUTE
)
endif (UNIX)
我不太了解原始 cmake 文件,因为我对这个话题还很陌生。
cpp文件路径为:/usr/local/src/ids/samples/peak/cpp/open_camera/open_camera.cpp
根据 CMake 文档,我们不应再对包含目录等使用全局设置,而应使用 target_
版本。老实说,我不认为第二个复杂的 CMakeLists.txt 被使用(或需要),它似乎不包含在第一个中(但如果不知道目录结构。
但是,无论如何,如果你想使用一些库,你需要两样东西:带有所提供项目声明的头文件和通常包含 definition/implementation 的已编译库项目(静态或动态库)。原则上,如果您可以访问库源文件,您也可以自己编译库。在这种情况下,我的建议是:
add_library(ids_peak
${IDS_PEAK_SOURCE_FILES}
)
target_include_directories(ids_peak PUBLIC /usr/include/ids_peak-1.3.0)
...
add_executable(open_camera
src/open_camera.cpp
)
target_include_directories(open_camera PRIVATE ${catkin_INCLUDE_DIRS})
target_link_libraries(open_camera PRIVATE ids_peak)
这将定义两个要编译的目标:
- 一个库目标,编译列表 ${ID_PEAK_SOURCE_FILES} 中的任何源文件并附加相应的包含目录
- 一个可执行目标,正在编译您的 open_camera.cpp 源文件。附有这个 catkin 包含目录(也许我们应该在这里选择其他库目标?是否有编译源或是否只有 lib+headers?)。最后但并非最不重要的是,向该目标添加了一个依赖项。
由于库目标的包含目录被声明为 public,它们被转发到依赖于它的所有目标(target_compile_definitions
、target_link_libraries
、target_link_options
, 等等).
您可能会对这些链接感兴趣:
- https://cmake.org/cmake/help/latest/command/add_library.html
- https://cmake.org/cmake/help/latest/command/add_executable.html
- https://cmake.org/cmake/help/latest/command/target_include_directories.html
- https://cmake.org/cmake/help/latest/command/target_link_libraries.html
- What do linkers do?
而且,如果您愿意挂断 FILE(GLOB...)
电话。有一次,一些 CMake 贡献者告诉我,这个功能没有发布,但是被逃脱了,根本不应该使用,因为它很容易出错。我知道它会派上用场,但您无法真正控制您的构建真正在做什么。最好明确命名文件。或者,在安装 (https://cmake.org/cmake/help/latest/command/install.html#directory) 或复制的情况下,您可以应用到整个目录。