【问题标题】:cmake linker error with library installed in custom path安装在自定义路径中的库的 cmake 链接器错误
【发布时间】:2020-04-25 19:17:57
【问题描述】:

我已经使用 CMake 将库 SDL_bgi 编译并安装到自定义前缀 /custom/prefix/。该库使用 SDL2。

现在我想在另一个具有以下结构的项目中使用它,但是当我使用 make 编译时出现链接器错误:

/usr/bin/c++     CMakeFiles/test.dir/test.cpp.o  -o test  -Wl,-rpath,/custom/prefix/lib: /custom/prefix/lib/libSDL_bgi.so 

/usr/bin/ld: /custom/prefix/lib/libSDL_bgi.so: undefined reference to `SDL_DestroyWindow'
/usr/bin/ld: /custom/prefix/lib/libSDL_bgi.so: undefined reference to `SDL_CreateRenderer'

我还写了文件cmake/modules/FindSDL_bgi.cmake,所以这也可能是错误的。

如果我使用以下命令编译,我可以正确编译:

g++ test.cpp -I . -lSDL_bgi -lSDL2 -I /custom/prefix/include/ -L /custom/prefix/lib/ 

我做错了什么?

项目结构:

cmake/modules/FindSDL_bgi.cmake
src/test/CMakeLists.txt
src/test/test.cpp
CMakeLists.txt

图书馆:

/usr/lib/libSDL.so
/usr/include/SDL.h
/custom/prefix/lib/libSDL_bgi.so
/custom/prefix/include/graphics.h
/custom/prefix/include/SDL2/libSDL_bgi.h

cmake/modules/FindSDL_bgi.cmake:

# - Try to find LibXml2
# Once done this will define
#  SDL_BGI_FOUND - System has LibXml2
#  SDL_BGI_INCLUDE_DIRS - The LibXml2 include directories
#  SDL_BGI_LIBRARIES - The libraries needed to use LibXml2

# Hardcoded for now
set(SDL_BGI_PATH
    /custom/prefix/
)

set(SDL_BGI_SEARCH_PATHS
    /usr
    /usr/local
    /opt
    ${SDL_BGI_PATH}
)

find_path(SDL_BGI_INCLUDE_DIR graphics.h
    HINTS
    $ENV{SDL2DIR}
    PATH_SUFFIXES include
    PATHS ${SDL2_SEARCH_PATHS}
)

find_library(SDL_BGI_LIBRARY
    NAMES SDL_bgi
    HINTS
    $ENV{SDL2DIR}
    PATH_SUFFIXES lib64 lib
    PATHS ${SDL2_SEARCH_PATHS}
)

include(FindPackageHandleStandardArgs)

find_package_handle_standard_args(SDL_bgi REQUIRED_VARS SDL_BGI_LIBRARY SDL_BGI_INCLUDE_DIR)

CMakeLists.txt

cmake_minimum_required(VERSION 3.15)

project(programmi_kennedy)

list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules")

set(COMPAT_HEADERS
    ${CMAKE_CURRENT_SOURCE_DIR}/include/
)

find_package(SDL_bgi REQUIRED)

add_subdirectory(src/test)

src/CMakeLists.txt:

add_executable(test test.cpp)
target_include_directories(test PUBLIC ${SDL_BGI_INCLUDE_DIR})
target_link_libraries(test PRIVATE ${SDL_BGI_LIBRARY})
install(TARGETS test DESTINATION bin)

/custom/prefix/include/graphics.h:

#include <SDL2/SDL_bgi.h>

【问题讨论】:

  • 所以...做find_package(SDL2)并链接${SDL2_LIBRARIES},你只链接SDL_BGI。
  • 我仍然不清楚的是为什么我需要链接到 SDL2 而不仅仅是针对 SDL_BGI?我的test.cpp只直接使用了SDL_BGI,SDL_BGI已经编译安装好了。丢失的符号不应该在运行时以某种方式解决吗?
  • 不,他们不应该。因为 cmake 将不知道您想要解决它们的“方式”或“到哪个”符号。解决所有依赖项是程序员的工作。您可以(并且以这种方式完成单元测试)编写 SDL2 库的自定义模拟实现并与之链接。或者您可以与系统安装的 SDL2 链接。或者您已将 SDL2 安装在一个目录中,并且您想与之链接。你已经告诉 cmake 了。

标签: cmake linker


【解决方案1】:

我缺少的是用find_package(SDL2 REQUIRED) 链接到SDL2 并链接到SDL2::SDL2。 (我确实尝试链接​​到${SDL2_LIBRARIES},但现在语法不同了)。感谢@KamilCuk 为我指明了正确的方向。

编辑:

我更改了 FindBGI_sdl.cmake 模块以搜索依赖项 (SDL2) 并使用 INTERFACE 关键字链接它们。这样,目标test 只能链接到SDL_bgi 并自动解决依赖关系。

src/CMakeLists.txt:

add_executable(test test.cpp)
target_link_libraries(test PRIVATE SDL_bgi::SDL_bgi)
install(TARGETS test DESTINATION bin)

cmake/modules/FindSDL_bgi.cmake:

# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.

#[=======================================================================[.rst:
FindSDL_bgi
-------

Finds the SDL_bgi library.

Imported Targets
^^^^^^^^^^^^^^^^

This module provides the following imported targets, if found:

``SDL_bgi::SDL_bgi``
  The SDL_bgi library

Result Variables
^^^^^^^^^^^^^^^^

This will define the following variables:

``SDL_bgi_FOUND``
  True if the system has the SDL_bgi library.
``SDL_bgi_VERSION``
  The version of the SDL_bgi library which was found.
``SDL_bgi_INCLUDE_DIRS``
  Include directories needed to use SDL_bgi.
``SDL_bgi_LIBRARIES``
  Libraries needed to link to SDL_bgi.

Cache Variables
^^^^^^^^^^^^^^^

The following cache variables may also be set:

``SDL_bgi_INCLUDE_DIR``
  The directory containing ``foo.h``.
``SDL_bgi_LIBRARY``
  The path to the SDL_bgi library.

#]=======================================================================]

find_package(SDL2 REQUIRED)
find_package(PkgConfig)
pkg_check_modules(PC_SDL_bgi QUIET SDL_bgi)

find_path(SDL_bgi_INCLUDE_DIR
    NAMES graphics.h
    PATHS ${PC_SDL_bgi_INCLUDE_DIRS}
)

find_library(SDL_bgi_LIBRARY
    NAMES SDL_bgi
    PATHS ${PC_SDL_bgi_LIBRARY_DIRS}
)

set(SDL_bgi_VERSION ${PC_SDL_bgi_VERSION})

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(SDL_bgi
  FOUND_VAR SDL_bgi_FOUND
  REQUIRED_VARS
    SDL_bgi_LIBRARY
    SDL_bgi_INCLUDE_DIR
  VERSION_VAR SDL_bgi_VERSION
)

if(SDL_bgi_FOUND AND NOT TARGET SDL_bgi::SDL_bgi)
  add_library(SDL_bgi::SDL_bgi UNKNOWN IMPORTED)
  set_target_properties(SDL_bgi::SDL_bgi PROPERTIES
    IMPORTED_LOCATION "${SDL_bgi_LIBRARY}"
    INTERFACE_COMPILE_OPTIONS "${PC_SDL_bgi_CFLAGS_OTHER}"
    INTERFACE_INCLUDE_DIRECTORIES "${SDL_bgi_INCLUDE_DIR}"
  )
  target_link_libraries(SDL_bgi::SDL_bgi INTERFACE SDL2::SDL2)
endif()

mark_as_advanced(
  SDL_bgi_INCLUDE_DIR
  SDL_bgi_LIBRARY
  SDL2_DIR
)

有用的参考资料:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-26
    • 2016-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-22
    相关资源
    最近更新 更多