windows 如何跨平台+CMake自动下载C++依赖?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8153519/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 18:29:01  来源:igfitidea点击:

How to automatically download C++ dependencies in a cross platform way + CMake?

c++windowsdependenciescmake

提问by JBeurer

Basically I want to achieve this workflow:

基本上我想实现这个工作流程:

  1. Checkout from repository on windows system (or any platform for that matter).

  2. Run some tool that gets dependencies, both includes and libs and puts them in their proper place (like in "\Program Files\Microsoft Visual Studio 10.0\VC\Lib and \Includes" on windows)

  3. Run CMake (creates MSVS projects on win)

  4. Open up MSVS project and compile it.

  1. 从 Windows 系统(或任何平台)上的存储库签出。

  2. 运行一些获取依赖项的工具,包括包括和库,并将它们放在适当的位置(如 Windows 上的“\Program Files\Microsoft Visual Studio 10.0\VC\Lib and \Includes”)

  3. 运行 CMake(在 win 上创建 MSVS 项目)

  4. 打开 MSVS 项目并编译它。

And i would like to have this workflow on most platforms.

我希望在大多数平台上都有这个工作流程。

I dont want to have to download dependencies manually

我不想手动下载依赖项

How to do this without storing dependencies in repository? What is the best way to achieve this?

如何在不将依赖项存储在存储库中的情况下执行此操作?实现这一目标的最佳方法是什么?

采纳答案by Silas Parker

In CMake you can use file(DOWNLOAD URL PATH)to download a file, combine this with custom commands to download and unpack:

在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}")

Your target should depend on the output from the custom command, then when you run CMake the file will be downloaded, and when you build, extracted and used.

你的目标应该取决于自定义命令的输出,然后当你运行 CMake 时,文件将被下载,当你构建、提取和使用时。

This could all be wrapped up in a macro to make it easier to use.

这一切都可以包含在一个宏中,以使其更易于使用。

You could also look at using the CMake module ExternalProjectwhich may do what you want.

您还可以考虑使用 CMake 模块ExternalProject,它可以满足您的需求。

回答by Vertexwahn

Within the CMake universe:

在 CMake 世界中:

vcpkg

vcpkg

vcpkgis a package manager for C++ Library Manager for Windows, Linux, and macOS. It can be seamlessly integrated with CMake - see herefor details.

vcpkg是适用于 Windows、Linux 和 macOS 的 C++ 库管理器的包管理器。它可以与 CMake 无缝集成 -有关详细信息,请参见此处

Conan

柯南

Conanis a C/C++ package manager. It also has a strategyfor the integration with CMake.

Conan是一个 C/C++ 包管理器。它还具有与 CMake 集成的策略

CMake with ExternalProject_Add

带有 ExternalProject_Add 的 CMake

CMakeList.txt.in

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

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

例子.cpp

#include <iostream>

#include "gtest/gtest.h"

TEST(sample_test_case, sample_test)
{
    EXPECT_EQ(1, 1);
}

Outside of the CMake universe:

在 CMake 世界之外:

I suggest you not to use CMake! Use Bazel!

我建议你不要使用 CMake!使用巴泽尔

For instance if you want to use gtest:

例如,如果您想使用gtest

WORKSPACE

工作空间

workspace(name = "GTestDemo")

工作区(名称 =“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",
)

BUILD

建造

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);
}

How to run the test?

如何运行测试?

bazel test //...

For instance if you want to use boost:

例如,如果您想使用boost

WORKSPACE

工作空间

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()

BUILD

建造

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 path\n";
        return 1;
    }
    std::cout << argv[1] << " " << file_size(argv[1]) << '\n';
    return 0;
}

How to build:

如何构建:

bazel build //...

How to run:

如何运行:

bazel run //:FilesystemTest

If you want to generate a Visual Studio solution use lavender. Unfortunately lavender is only experimental and it needs some improvement. But I think it makes more sense to spend effort here instead of getting CMake working with all your dependencies. There are also some projectsthat try to make an Bazel CMake interop.

如果要生成 Visual Studio 解决方案,请使用lavender。不幸的是,薰衣草只是实验性的,需要一些改进。但是我认为在这里花费精力而不是让 CMake 处理所有依赖项更有意义。还有一些项目试图制作 Bazel CMake 互操作。

回答by Andreas Walter

From cmake 3.11 on there is a new feature: FetchContent

从 cmake 3.11 开始,有一个新功能:FetchContent

You can use it to get your dependencies during configuration, e.g. get the great cmake-scripts.

您可以使用它在配置期间获取您的依赖项,例如获取出色的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})

I prefer fetching the ziped sources instead of directly checking out. But FetchContentalso allows to define a git repository.

我更喜欢获取压缩的源代码而不是直接签出。但FetchContent也允许定义一个 git 存储库。

回答by DLRdave

The best way to achieve this is to eliminate your dependencies.

实现这一目标的最佳方法是消除您的依赖项。

Dependencies are evil.

依赖是邪恶的。

Eliminate them instead of depending on them.

消除它们而不是依赖它们。

Seriously.

严重地。

You don't want to download them manually, you don't want to store them in your repository, your clients don't want to download them for you. In fact, your compiler doesn't even want to compile them.

您不想手动下载它们,不想将它们存储在您的存储库中,您的客户不想为您下载它们。事实上,您的编译器甚至不想编译它们。

Prefer switching to java to adding a C++ library dependency...

更喜欢切换到 java 以添加 C++ 库依赖项...

In the meantime, the suggestion to check out the ExternalProjectmodule of CMake is the closest you're gonna get to a non-repository-stored automatic-dependency-download-configure-build-and-install anytime soon with a CMake-based build.

同时,检查CMake的ExternalProject模块的建议是您最接近非存储库存储的自动依赖项下载配置构建和安装的最接近基于 CMake 的构建.