Cmake vcpkg 和 Bullet

问题描述

在这里很迷茫,真的需要一些帮助。

我正在为明年的荣誉项目工作,该项目涉及使用 Bullet 和 Vulkan 进行渲染的物理模拟。经过几个月的工作,我已经完成了大部分项目的运作。它需要大量重构和清理,这将是下一阶段。

我一直在使用 makefile,但出于一些原因希望迁移到 CMake。主要是因为它似乎是标准,并且因为我想在将来为不同的操作系统进行编译(我正在运行 Linux,但可能需要在 Windows 或 Mac 上部署)。最后,我正在重新编译整个项目,即使是一个小小的改动,随着我开始更多地进行单元测试,这开始成为一个问题。

旧的makefile如下:

ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))

OWN_INCLUDES = \
    -I$(ROOT_DIR)/src/Domain \
    -I$(ROOT_DIR)/src/Vk \
    -I$(ROOT_DIR)/src/Ui \
    -I$(ROOT_DIR)/src/Service

ADD_INCLUDES = \
    -I/Opt/bullet3-master/src \
    -I/Opt/vk_mem_alloc \
    -I/Opt/stb_image \
    -I/Opt/tiny_obj_loader/ \
    -I/Opt/imgui-vulkan/ 

BULLET_INCLUDE_PATHS_LIBS = -L/opt/bullet3-master/src/BulletCollision/ \
                            -L/opt/bullet3-master/src/BulletDynamics/ \
                            -L/opt/bullet3-master/src/LinearMath/ \
                            -lBulletDynamics -lBulletCollision -lLinearMath

VULKAN_SDK_PATH = /opt/Vulkan_SDK/1.2.162.1/x86_64

CFLAGS = -std=c++17 -I$(VULKAN_SDK_PATH)/include $(OWN_INCLUDES) $(ADD_INCLUDES)
LDFLAGS = -L$(VULKAN_SDK_PATH)/lib `pkg-config --static --libs glfw3` -lvulkan $(BULLET_INCLUDE_PATHS_LIBS)

IMGUI_CPP_PATHS = /opt/imgui-vulkan/*.cpp

OWN_CPP_PATHS = src/*.cpp src/Domain/*.cpp src/Vk/*.cpp src/Ui/*.cpp src/Service/*.cpp

###### Unit Testing Paths
UNIT_TEST_INCLUDE = -I/Opt/catch-header/
UNIT_TESTS_PATH = $(ROOT_DIR)/unit_tests/*.cpp


VulkanRun: $(OWN_CPP_PATHS) $(IMGUI_CPP_PATHS)
    g++ $(CFLAGS) -o VulkanRun $(OWN_CPP_PATHS) $(IMGUI_CPP_PATHS) $(LDFLAGS)

Unit_Test: $(UNIT_TESTS_PATH) src/Domain/*.cpp src/Vk/*.cpp src/Ui/*.cpp src/Service/*.cpp $(IMGUI_CPP_PATHS)
    g++ $(UNIT_TEST_INCLUDE) $(CFLAGS) -o Unit_Test $(UNIT_TESTS_PATH) src/Domain/*.cpp src/Vk/*.cpp src/Ui/*.cpp src/Service/*.cpp $(IMGUI_CPP_PATHS) $(LDFLAGS) 

VulkanDebug: $(OWN_CPP_PATHS) $(IMGUI_CPP_PATHS)
    g++ $(CFLAGS) -g -o VulkanDebug $(OWN_CPP_PATHS) $(IMGUI_CPP_PATHS) $(LDFLAGS)

Vulkanopt: $(OWN_CPP_PATHS) $(IMGUI_CPP_PATHS)
    g++ $(CFLAGS) -O3 -o Vulkanopt $(OWN_CPP_PATHS) $(IMGUI_CPP_PATHS) $(LDFLAGS)

.PHONY: test clean

run: VulkanRun
    LD_LIBRARY_PATH=$(VULKAN_SDK_PATH)/lib
    VK_LAYER_PATH=$(VULKAN_SDK_PATH)/etc/vulkan/explicit_layer.d 
    ./VulkanRun

test: Unit_Test
    LD_LIBRARY_PATH=$(VULKAN_SDK_PATH)/lib
    VK_LAYER_PATH=$(VULKAN_SDK_PATH)/etc/vulkan/explicit_layer.d 
    ./Unit_Test

debug: VulkanDebug
    LD_LIBRARY_PATH=$(VULKAN_SDK_PATH)/lib
    VK_LAYER_PATH=$(VULKAN_SDK_PATH)/etc/vulkan/explicit_layer.d 

optimise: Vulkanopt
    LD_LIBRARY_PATH=$(VULKAN_SDK_PATH)/lib
    VK_LAYER_PATH=$(VULKAN_SDK_PATH)/etc/vulkan/explicit_layer.d 
    ./Vulkanopt

7 clean:
    rm -f VulkanRun
    rm -f Unit_Test
    rm -f VulkanDebug
    rm -f Vulkanopt

我使用 3.21.0 的最新安装脚本安装了 cmake。

我在项目的根目录中创建了一个 CMakeLists.txt 如下:

cmake_minimum_required(VERSION 3.21.0)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")

project(LanderSim)

file(GLOB_RECURSE SOURCES "src/**.cpp")

add_executable(main ${SOURCES})

find_package(Bullet CONfig required)

if (BULLET_FOUND)
  include_directories(${BULLET_INCLUDE_Dirs})
  target_link_libraries(main PRIVATE LinearMath Bullet3Common BulletDynamics BulletSoftBody)
endif (BULLET_FOUND)

经过数小时的尝试,我决定尝试 vcpkg。按照项目符号中的安装说明进行操作:

git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install bullet3

这导致了错误

CMakeLists.txt 中的 CMake 错误:11 (find_package): 找不到“Bullet”提供的包配置文件 以下名称: BulletConfig.cmake bullet-config.cmake

在 CMakeCache.txt 中我看到“Bullet_DIR:PATH=Bullet_DIR-NOTFOUND”

我在“/home/ash/vcpkg/installed/x64-linux/share/bullet3”和“/home/ash/vcpkg/packages/bullet3_x64-linux/share/bullet3”和将 MakeCache.txt var Bullet_DIR:PATH 设置为这些变量(一次测试一个)。

再次运行时,我无法识别 CMake set_and_check() 函数。或者类似的东西。查看 BulletConfig.make 文件,我看到 linter 无法识别这些 set_and_check() 函数。我在网上找不到关于它们被弃用的任何信息,但我认为是这种情况。所以我更改为 set(),然后 CMake 成功并构建其文件

运行 make 然后我得到一个错误

致命错误:btBulletDynamicsCommon.h:没有那个文件或目录, #include

我尝试在包含路径之前添加 bullet/ ,因为其他人有此问题,但它会导致相同的错误

所以我一定是做错了什么,而且我显然不理解 CMake 用来添加包含和链接库的过程。我敢肯定,鉴于 CMake 的流行,一定有一些显而易见的东西。但几天来我花了大约 10 个小时来搜索和尝试不同的变体,我开始感到非常沮丧。

我之前已经放弃了 CMake(因此我几个月来一直在使用 makefile),但我决心正确地做到这一点。如果有人知道如何让 CMake 生成可以看到使用 vcpkg 安装的软件包的 makefile,我真的可以使用一些帮助。

或者确实,如果 Bullet 的 vcpkg 已过时,那么单独将其与 CMake 链接和包含的方法会很棒。我只是认为 vcpkg 会更容易,因为它认提供更清晰的文件结构以及 CMake 配置文件

谢谢。

编辑 1

我用过'cmake'。和'cmake 。 -DCMAKE_TOOLCHAIN_FILE=/home/ash/vcpkg/scripts/buildsystems/vcpkg.cmake' 来构建 makefile。两者在调用 make 时都会导致相同的缺少标头错误

编辑2

在每次调用 cmake 之前,所有 CMake 文件都从项目中删除(CMakeLists.txt 除外),以确保没有值存储在那里。

编辑 3

再戳了几下。这是 BulletConfig.cmake 文件

#
#  BulletConfig.cmake(.in)
#

# Use the following variables to compile and link against Bullet:
#  BULLET_FOUND              - True if Bullet was found on your system
#  BULLET_USE_FILE           - The file making Bullet usable
#  BULLET_DEFinitioNS        - DeFinitions needed to build with Bullet
#  BULLET_INCLUDE_DIR        - Directory where Bullet-C-Api.h can be found
#  BULLET_INCLUDE_Dirs       - List of directories of Bullet and it's dependencies
#  BULLET_LIBRARIES          - List of libraries to link against Bullet library
#  BULLET_LIBRARY_Dirs       - List of directories containing Bullet' libraries
#  BULLET_ROOT_DIR           - The base directory of Bullet
#  BULLET_VERSION_STRING     - A human-readable string containing the version

set(PACKAGE_PREFIX_DIR /home/ash/installed/x64-linux)

set ( BULLET_FOUND 1 )
set ( BULLET_USE_FILE     "${PACKAGE_PREFIX_DIR}/share/bullet3/UseBullet.cmake" )
set ( BULLET_DEFinitioNS  "" )
set ( BULLET_INCLUDE_DIR  "${PACKAGE_PREFIX_DIR}/include/bullet" )
set ( BULLET_INCLUDE_Dirs "${PACKAGE_PREFIX_DIR}/include/bullet" )
set ( BULLET_LIBRARIES    "LinearMath;Bullet3Common;BulletInverseDynamics;BulletCollision;BulletDynamics;BulletSoftBody" )
set ( BULLET_LIBRARY_Dirs "${PACKAGE_PREFIX_DIR}/lib" )
set ( BULLET_ROOT_DIR     "${PACKAGE_PREFIX_DIR}" )
set ( BULLET_VERSION_STRING "3.17" )

# Load targets
if(NOT TARGET Bullet3Common)
  file(GLOB CONfig_FILES "${PACKAGE_PREFIX_DIR}/share/bullet3/*Targets.cmake")
  foreach(f ${CONfig_FILES})
    include(${f})
  endforeach()
  set(_DIR)
endif()

如前所述,一些集合函数是 set_and_check()。所以我改为 set() ,因为显然 cmake 3.21 没有 set_and_check() 函数。通过打印 message() 进行一些测试后,我发现 PACKAGE_PREFIX_DIR 没有在任何地方设置。所以这就是我在这文件中明确设置它的原因。现在变量设置正确,如 CMakeLists.txt 文件中的 message() 报告的那样。但是还是找不到头文件

编辑4

我创建了一个空项目并浏览了我想要包含的每个库。除 Bullet3 外,一切正常。但是它现在可以看到头文件。两个 CMakeFiles 之间有什么变化?据我所知,没有什么。我需要找出原因,因为我必须移植这个项目,但与此同时,这是包的另一个问题。

from /home/ash/projects/C++/CMakeImportTests/src/main.cpp:22:
/home/ash/vcpkg/installed/x64-linux/include/bullet/BulletCollision/Collisiondispatch/btCollisionWorld.h:77:10:

致命错误:LinearMath/btVector3.h:没有那个文件或目录 77 | #include "LinearMath/btVector3.h"

我认为这与描述的问题相同#7877

如果我删除了 Bullet 的所有包含但保留 CMakeList.txt 不变,我们会收到此错误

[ 50%] Building CXX object CMakeFiles/main.dir/src/main.cpp.o
[100%] Linking CXX executable main
/usr/bin/ld: cannot find -lLinearMath
/usr/bin/ld: cannot find -lBullet3Common
/usr/bin/ld: cannot find -lBulletDynamics
/usr/bin/ld: cannot find -lBulletSoftBody
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/main.dir/build.make:104: main] Error 1
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/main.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

这是一个没有设置环境变量的线索吗?

编辑5

target_link_library 调用似乎存在顺序依赖性。建议的用法是:

target_link_libraries(main PRIVATE LinearMath Bullet3Common BulletDynamics BulletSoftBody)

检查我找到的 libs/ 目录中的 bullet.pc

Libs: -L${libdir} -lBulletSoftBody -lBulletDynamics -lBulletCollision -lLinearMath

所以我尝试重新排列并遵循模式:

target_link_libraries(main PRIVATE BulletSoftBody BulletDynamics BulletCollision Bullet3Common LinearMath)

此外,还需要手动链接目录。

target_link_directories(main PRIVATE ${BULLET_LIBRARY_Dirs})

现在在我的测试项目中编译没有错误。似乎 LinearMath 必须在大多数其他库之后(尽管它似乎可以在 Bullet3Common 之前)。

由于某种原因,当我将完全相同的 CMake 命令复制到我的主项目时,它仍然找不到头文件。所以我还没有摆脱这个。

我应该说我能够删除我对 BulletConfig.cmake 所做的静态设置 PACKAGE_PREFIX_DIR 的更改。

所以只是回顾一下我的问题。一个小型测试项目有效,我可以使用我在主项目中使用的项目符号和其他一些库。但是,如果我将此工作 CMakeLists.txt 复制到我的主项目中,它就无法再找到标题并引发此错误

btBulletDynamicsCommon.h: No such file or directory
8 | #include <btBulletDynamicsCommon.h>

Bullet_DIR:PATH=/home/ash/vcpkg/installed/x64-linux/share/bullet3 在这两种情况下都是一样的。

解决方法

毕竟。

set_and_include() 错误是一个已知问题,vcpkg git 上的 mathisloge 表示需要更新 Bullet 包。解决方法是更改​​对 set() 的调用。

目标库的顺序很重要。 Bullet vcpkg 包中的建议方法是:

target_link_libraries(main PRIVATE LinearMath Bullet3Common BulletDynamics BulletSoftBody)

但这无法编译。应该是:

target_link_libraries(main PRIVATE BulletSoftBody BulletDynamics BulletCollision Bullet3Common LinearMath)

还必须使用 :

告诉 cmake 链接目录
target_link_directories(main PRIVATE ${BULLET_LIBRARY_DIRS})

然后我仍然有标题丢失错误。但是在重新启动后,事情又开始工作了。希望这里有足够的内容来帮助遇到类似问题的人。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...