如何以跨平台的方式自动下载c++依赖项+ CMake
How to automatically download C++ dependencies in a cross platform way + CMake?
基本上我想实现这个工作流程:
-
从windows系统(或任何平台)的存储库签出。
-
运行一些工具,获得依赖关系,包括和库,并把它们放在适当的位置(如在"Program FilesMicrosoft Visual Studio 10.0VCLib和 includes"在windows上)
-
运行CMake(在win上创建MSVS项目)
-
打开MSVS项目并编译
我希望在大多数平台上都有这个工作流程。
我不想手动下载依赖项
如何做到这一点,而不存储在仓库中的依赖关系?实现这一目标的最佳方式是什么?
在CMake中,您可以使用file(DOWNLOAD URL PATH)
来下载文件,并将其与自定义命令结合使用来下载和解包:
set(MY_URL "http://...")
set(MY_DOWNLOAD_PATH "path/to/download/to")
set(MY_EXTRACTED_FILE "path/to/extracted/file")
if (NOT EXISTS "${MY_DOWNLOAD_PATH}")
file(DOWNLOAD "${MY_URL}" "${MY_DOWNLOAD_PATH}")
endif()
add_custom_command(
OUTPUT "${MY_EXTRACTED_FILE}"
COMMAND command to unpack
DEPENDS "${MY_DOWNLOAD_PATH}")
你的目标应该取决于自定义命令的输出,然后当你运行CMake时,文件将被下载,当你构建,提取和使用。
这些都可以包装在一个宏中,使其更容易使用。
你也可以看看使用CMake模块ExternalProject,它可以做你想做的。
从cmake 3.11开始有一个新功能:FetchContent
你可以在配置时使用它来获取你的依赖项,例如获取cmake-scripts。
include(FetchContent)
FetchContent_Declare(
cmake_scripts
URL https://github.com/StableCoder/cmake-scripts/archive/master.zip)
FetchContent_Populate(cmake_scripts)
message(STATUS "cmake_scripts is available in " ${cmake_scripts_SOURCE_DIR})
我更喜欢获取压缩的源代码,而不是直接签出。但是FetchContent
也允许定义git存储库。
vcpkg
vcpkg是一个用于Windows、Linux和macOS的c++库管理器的包管理器。它可以与CMake无缝集成-查看这里的详细信息。
柯南
Conan是一个C/c++包管理器。它还有一个与CMake集成的策略。
CMake with ExternalProject_Add
CMakeList.txt.in:
cmake_minimum_required(VERSION 2.8.2)
project(googletest-download NONE)
include(ExternalProject)
ExternalProject_Add(googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG master
SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src"
BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)
CMakeList.txt:
cmake_minimum_required(VERSION 3.8)
# Download and unpack googletest at configure time
configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download )
if(result)
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
endif()
execute_process(COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download )
if(result)
message(FATAL_ERROR "Build step for googletest failed: ${result}")
endif()
# Prevent overriding the parent project's compiler/linker
# settings on Windows
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
# Add googletest directly to our build. This defines
# the gtest and gtest_main targets.
add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
${CMAKE_BINARY_DIR}/googletest-build)
# The gtest/gtest_main targets carry header search path
# dependencies automatically when using CMake 2.8.11 or
# later. Otherwise we have to add them here ourselves.
if (CMAKE_VERSION VERSION_LESS 2.8.11)
include_directories("${gtest_SOURCE_DIR}/include")
endif()
# Now simply link against gtest or gtest_main as needed. Eg
add_executable(example example.cpp)
target_link_libraries(example gtest_main)
add_test(NAME example_test COMMAND example)
example.cpp
#include <iostream>
#include "gtest/gtest.h"
TEST(sample_test_case, sample_test)
{
EXPECT_EQ(1, 1);
}
CMake宇宙之外:
我建议你不要使用CMake!用巴泽尔!
例如,如果你想使用gtest:
工作区
workspace(name = "GTestDemo")
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
git_repository(
name = "googletest",
#tag = "release-1.8.1",
commit = "2fe3bd994b3189899d93f1d5a881e725e046fdc2",
remote = "https://github.com/google/googletest",
shallow_since = "1535728917 -0400",
)
构建cc_test(
name = "tests",
srcs = ["test.cpp"],
copts = ["-isystem external/gtest/include"],
deps = [
"@googletest//:gtest_main",
],
)
text.cpp
#include <iostream>
#include "gtest/gtest.h"
TEST(sample_test_case, sample_test)
{
EXPECT_EQ(1, 1);
}
如何运行测试?
bazel test //...
例如,如果你想使用boost:
工作区
workspace(name = "BoostFilesystemDemo")
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
# Fetch Boost repo
git_repository(
name = "com_github_nelhage_rules_boost",
commit = "49066b7ccafce2609a3d605e3667af3f07e8547c",
remote = "https://github.com/Vertexwahn/rules_boost",
shallow_since = "1559083909 +0200",
)
load("@com_github_nelhage_rules_boost//:boost/boost.bzl", "boost_deps")
boost_deps()
构建cc_binary(
name = "FilesystemTest",
srcs = ["main.cpp"],
defines = ["BOOST_ALL_NO_LIB"],
deps = [
"@boost//:filesystem",
],
)
main.cpp
#include <iostream>
#include <boost/filesystem.hpp>
using namespace boost::filesystem;
int main(int argc, char* argv[])
{
if (argc < 2)
{
std::cout << "Usage: tut1 pathn";
return 1;
}
std::cout << argv[1] << " " << file_size(argv[1]) << 'n';
return 0;
}
如何构建:
bazel build //...
如何运行:
bazel run //:FilesystemTest
如果您想生成Visual Studio解决方案,请使用薰衣草。不幸的是,薰衣草只是试验性的,它需要一些改进。但我认为在这里花费精力比让CMake处理所有依赖项更有意义。也有一些项目试图做一个Bazel CMake互操作
实现这一目标的最佳方法是消除依赖关系。
依赖是邪恶的。
消除它们而不是依赖它们。
。
你不想手动下载它们,你不想将它们存储在你的存储库中,你的客户端不想为你下载它们。事实上,你的编译器甚至不想编译它们。
选择切换到java而不是添加c++库依赖…
与此同时,建议检查CMake的ExternalProject模块是最接近的,你会得到一个非存储库存储的自动-依赖-下载-配置-构建和安装在任何时候很快与CMake为基础的构建。
- 如何从C++中的依赖类型中获得它所依赖的类型
- 将--whole archive链接器选项与CMake和具有其他库依赖项的库一起使用
- 将依赖名称显式标记为类型名和模板的奇怪之处
- 在 Windows 上,是否可以让 dll 在不使用 PATH 环境变量的情况下在另一个文件夹中查找依赖项?
- C++GTKMM gui循环依赖关系
- 通过ccmake在cmake中缓存依赖选项
- 当基类是依赖类型时,这是一个缺陷吗
- 从不同的附加依赖项中识别等同命名的函数
- 如何在 CMake 中对目标依赖项进行分组?
- 是否可以依赖函数范围的静态变量来执行程序关闭期间调用的方法?
- 为什么构建目录中新构建的共享库与安装目录中的副本具有不同的依赖项集?
- VS 2015 链接错误 无法构建依赖于 libcurl 的项目
- 通过依赖类型使用非类型模板参数的单类型模板参数类模板的部分专用化
- 为什么内存屏障依赖于变量?
- node-gyp 的先有鸡还是先有蛋的问题:指向依赖项中的头文件
- 反转依赖于 end() 的迭代器
- GCC,CMake,预编译标头和维护依赖项
- 使用 'typename' 关键字将非类型视为依赖上下文中的类型
- 使用 Git 处理 C++ Visual Studio 2019 解决方案的外部依赖项源代码管理的最佳方法是什么?
- 为什么依赖模板类型在部分专用化中不可推导?