将 CppADCodeGen 与 CMake FetchContent 或 ExternalProject 结合使用

Use CppADCodeGen with CMake FetchContent or ExternalProject

我不擅长 CMake,我找不到关于如何使用它的 FetchContent 功能的好的解释。事实上,大多数存储库似乎需要不同的处理方式,而这种处理方式的规则让我无法理解。

也就是说,这是我的问题。我想在我使用 CMake FetchContent 的项目中使用 CppADCodeGen。这是我的代码:

include(FetchContent)

message(STATUS "Fetching eigen...")
FetchContent_Declare(
  eigen
  GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
  GIT_TAG 3.4.0
  GIT_SHALLOW TRUE
  GIT_PROGRESS TRUE)
option(EIGEN_BUILD_DOC OFF)
option(BUILD_TESTING OFF)
option(EIGEN_LEAVE_TEST_IN_ALL_TARGET OFF)
option(EIGEN_BUILD_PKGCONFIG OFF)
FetchContent_MakeAvailable(eigen)

message(STATUS "Fetching cppad...")
FetchContent_Declare(
  cppad
  GIT_REPOSITORY https://github.com/coin-or/CppAD.git
  GIT_TAG 20210000.8
  GIT_SHALLOW TRUE
  GIT_PROGRESS TRUE)
FetchContent_MakeAvailable(cppad)

message(STATUS "Fetching cppadcodgen...")
FetchContent_Declare(
  cppadcodgen
  GIT_REPOSITORY https://github.com/joaoleal/CppADCodeGen.git
  GIT_TAG v2.4.3
  GIT_SHALLOW TRUE
  GIT_PROGRESS TRUE)
FetchContent_MakeAvailable(cppadcodgen)

这是输出和我得到的错误:

[cmake] Not searching for unused variables given on the command line.
[cmake] -- The C compiler identification is GNU 11.1.0
[cmake] -- The CXX compiler identification is GNU 11.1.0
[cmake] -- Detecting C compiler ABI info
[cmake] -- Detecting C compiler ABI info - done
[cmake] -- Check for working C compiler: /bin/x86_64-linux-gnu-gcc-11 - skipped
[cmake] -- Detecting C compile features
[cmake] -- Detecting C compile features - done
[cmake] -- Detecting CXX compiler ABI info
[cmake] -- Detecting CXX compiler ABI info - done
[cmake] -- Check for working CXX compiler: /bin/x86_64-linux-gnu-g++-11 - skipped
[cmake] -- Detecting CXX compile features
[cmake] -- Detecting CXX compile features - done
[cmake] -- Fetching eigen...
[cmake] -- Performing Test EIGEN_COMPILER_SUPPORT_CPP11
[cmake] -- Performing Test EIGEN_COMPILER_SUPPORT_CPP11 - Success
[cmake] -- Performing Test COMPILER_SUPPORT_std=cpp03
[cmake] -- Performing Test COMPILER_SUPPORT_std=cpp03 - Success
[cmake] -- Performing Test standard_math_library_linked_to_automatically
[cmake] -- Performing Test standard_math_library_linked_to_automatically - Success
[cmake] -- Standard libraries to link to explicitly: none
[cmake] -- Performing Test COMPILER_SUPPORT_WERROR
[cmake] -- Performing Test COMPILER_SUPPORT_WERROR - Success
[cmake] -- Performing Test COMPILER_SUPPORT_pedantic
[cmake] -- Performing Test COMPILER_SUPPORT_pedantic - Success
[cmake] -- Performing Test COMPILER_SUPPORT_Wall
[cmake] -- Performing Test COMPILER_SUPPORT_Wall - Success
[cmake] -- Performing Test COMPILER_SUPPORT_Wextra
[cmake] -- Performing Test COMPILER_SUPPORT_Wextra - Success
[cmake] -- Performing Test COMPILER_SUPPORT_Wundef
[cmake] -- Performing Test COMPILER_SUPPORT_Wundef - Success
[cmake] -- Performing Test COMPILER_SUPPORT_Wcastalign
[cmake] -- Performing Test COMPILER_SUPPORT_Wcastalign - Success
[cmake] -- Performing Test COMPILER_SUPPORT_Wcharsubscripts
[cmake] -- Performing Test COMPILER_SUPPORT_Wcharsubscripts - Success
[cmake] -- Performing Test COMPILER_SUPPORT_Wnonvirtualdtor
[cmake] -- Performing Test COMPILER_SUPPORT_Wnonvirtualdtor - Success
[cmake] -- Performing Test COMPILER_SUPPORT_Wunusedlocaltypedefs
[cmake] -- Performing Test COMPILER_SUPPORT_Wunusedlocaltypedefs - Success
[cmake] -- Performing Test COMPILER_SUPPORT_Wpointerarith
[cmake] -- Performing Test COMPILER_SUPPORT_Wpointerarith - Success
[cmake] -- Performing Test COMPILER_SUPPORT_Wwritestrings
[cmake] -- Performing Test COMPILER_SUPPORT_Wwritestrings - Success
[cmake] -- Performing Test COMPILER_SUPPORT_Wformatsecurity
[cmake] -- Performing Test COMPILER_SUPPORT_Wformatsecurity - Success
[cmake] -- Performing Test COMPILER_SUPPORT_Wshorten64to32
[cmake] -- Performing Test COMPILER_SUPPORT_Wshorten64to32 - Failed
[cmake] -- Performing Test COMPILER_SUPPORT_Wlogicalop
[cmake] -- Performing Test COMPILER_SUPPORT_Wlogicalop - Success
[cmake] -- Performing Test COMPILER_SUPPORT_Wenumconversion
[cmake] -- Performing Test COMPILER_SUPPORT_Wenumconversion - Success
[cmake] -- Performing Test COMPILER_SUPPORT_Wcpp11extensions
[cmake] -- Performing Test COMPILER_SUPPORT_Wcpp11extensions - Failed
[cmake] -- Performing Test COMPILER_SUPPORT_Wdoublepromotion
[cmake] -- Performing Test COMPILER_SUPPORT_Wdoublepromotion - Success
[cmake] -- Performing Test COMPILER_SUPPORT_Wshadow
[cmake] -- Performing Test COMPILER_SUPPORT_Wshadow - Success
[cmake] -- Performing Test COMPILER_SUPPORT_Wnopsabi
[cmake] -- Performing Test COMPILER_SUPPORT_Wnopsabi - Success
[cmake] -- Performing Test COMPILER_SUPPORT_Wnovariadicmacros
[cmake] -- Performing Test COMPILER_SUPPORT_Wnovariadicmacros - Success
[cmake] -- Performing Test COMPILER_SUPPORT_Wnolonglong
[cmake] -- Performing Test COMPILER_SUPPORT_Wnolonglong - Success
[cmake] -- Performing Test COMPILER_SUPPORT_fnochecknew
[cmake] -- Performing Test COMPILER_SUPPORT_fnochecknew - Success
[cmake] -- Performing Test COMPILER_SUPPORT_fnocommon
[cmake] -- Performing Test COMPILER_SUPPORT_fnocommon - Success
[cmake] -- Performing Test COMPILER_SUPPORT_fstrictaliasing
[cmake] -- Performing Test COMPILER_SUPPORT_fstrictaliasing - Success
[cmake] -- Performing Test COMPILER_SUPPORT_wd981
[cmake] -- Performing Test COMPILER_SUPPORT_wd981 - Failed
[cmake] -- Performing Test COMPILER_SUPPORT_wd2304
[cmake] -- Performing Test COMPILER_SUPPORT_wd2304 - Failed
[cmake] -- Performing Test COMPILER_SUPPORT_STRICTANSI
[cmake] -- Performing Test COMPILER_SUPPORT_STRICTANSI - Failed
[cmake] -- Performing Test COMPILER_SUPPORT_Qunusedarguments
[cmake] -- Performing Test COMPILER_SUPPORT_Qunusedarguments - Failed
[cmake] -- Performing Test COMPILER_SUPPORT_ansi
[cmake] -- Performing Test COMPILER_SUPPORT_ansi - Success
[cmake] -- Performing Test COMPILER_SUPPORT_OPENMP
[cmake] -- Performing Test COMPILER_SUPPORT_OPENMP - Success
[cmake] -- Looking for a Fortran compiler
[cmake] -- Looking for a Fortran compiler - /usr/bin/f95
[cmake] -- The Fortran compiler identification is GNU 9.3.0
[cmake] -- Detecting Fortran compiler ABI info
[cmake] -- Detecting Fortran compiler ABI info - done
[cmake] -- Check for working Fortran compiler: /usr/bin/f95 - skipped
[cmake] -- Checking whether /usr/bin/f95 supports Fortran 90
[cmake] -- Checking whether /usr/bin/f95 supports Fortran 90 - yes
[cmake] -- Found unsuitable Qt version "5.12.8" from /usr/bin/qmake
[cmake] -- Qt4 not found, so disabling the mandelbrot and opengl demos
[cmake] -- Found CHOLMOD: /usr/include/suitesparse  
[cmake] -- Found UMFPACK: /usr/include/suitesparse  
[cmake] -- Found KLU: /usr/include/suitesparse  
[cmake] -- Performing Test SUPERLU_HAS_GLOBAL_MEM_USAGE_T
[cmake] -- Performing Test SUPERLU_HAS_GLOBAL_MEM_USAGE_T - Success
[cmake] -- Performing Test SUPERLU_HAS_CLEAN_ENUMS
[cmake] -- Performing Test SUPERLU_HAS_CLEAN_ENUMS - Success
[cmake] -- Performing Test SUPERLU_HAS_GLOBALLU_T
[cmake] -- Performing Test SUPERLU_HAS_GLOBALLU_T - Success
[cmake] -- Found SuperLU: /usr/include/superlu (found suitable version "5.0", minimum required is "4.0") 
[cmake] -- Checking for one of the modules 'hwloc'
[cmake] -- Performing Test HAVE_HWLOC_PARENT_MEMBER
[cmake] -- Performing Test HAVE_HWLOC_PARENT_MEMBER - Success
[cmake] -- Performing Test HAVE_HWLOC_CACHE_ATTR
[cmake] -- Performing Test HAVE_HWLOC_CACHE_ATTR - Success
[cmake] -- Performing Test HAVE_HWLOC_OBJ_PU
[cmake] -- Performing Test HAVE_HWLOC_OBJ_PU - Success
[cmake] -- Looking for hwloc_bitmap_free in hwloc
[cmake] -- Looking for hwloc_bitmap_free in hwloc - found
[cmake] -- A version of Pastix has been found but pastix_nompi.h does not exist in the include directory. Because Eigen tests require a version without MPI, we disable the Pastix backend.
[cmake] -- 
[cmake] -- Configured Eigen 3.4.0
[cmake] -- 
[cmake] -- Available targets (use: make TARGET):
[cmake] -- ---------+--------------------------------------------------------------
[cmake] -- Target   |   Description
[cmake] -- ---------+--------------------------------------------------------------
[cmake] -- install  | Install Eigen. Headers will be installed to:
[cmake] --          |     <CMAKE_INSTALL_PREFIX>/<INCLUDE_INSTALL_DIR>
[cmake] --          |   Using the following values:
[cmake] --          |     CMAKE_INSTALL_PREFIX: /usr/local
[cmake] --          |     INCLUDE_INSTALL_DIR:  include/eigen3
[cmake] --          |   Change the install location of Eigen headers using:
[cmake] --          |     cmake . -DCMAKE_INSTALL_PREFIX=yourprefix
[cmake] --          |   Or:
[cmake] --          |     cmake . -DINCLUDE_INSTALL_DIR=yourdir
[cmake] -- doc      | Generate the API documentation, requires Doxygen & LaTeX
[cmake] -- blas     | Build BLAS library (not the same thing as Eigen)
[cmake] -- uninstall| Remove files installed by the install target
[cmake] -- ---------+--------------------------------------------------------------
[cmake] -- 
[cmake] -- Fetching cppad...
[cmake] CMake Deprecation Warning at build/_deps/cppad-src/CMakeLists.txt:20 (CMAKE_MINIMUM_REQUIRED):
[cmake]   Compatibility with CMake < 2.8.12 will be removed from a future version of
[cmake]   CMake.
[cmake] 
[cmake]   Update the VERSION argument <min> value or use a ...<max> suffix to tell
[cmake]   CMake that the project does not need compatibility with older versions.
[cmake] 
[cmake] 
[cmake] CMake Warning (dev) at build/_deps/cppad-src/CMakeLists.txt:35 (PROJECT):
[cmake]   Policy CMP0048 is not set: project() command manages VERSION variables.
[cmake]   Run "cmake --help-policy CMP0048" for policy details.  Use the cmake_policy
[cmake]   command to set the policy and suppress this warning.
[cmake] 
[cmake]   The following variable(s) would be set to empty:
[cmake] 
[cmake]     PROJECT_VERSION
[cmake]     PROJECT_VERSION_MAJOR
[cmake]     PROJECT_VERSION_MINOR
[cmake]     PROJECT_VERSION_PATCH
[cmake] This warning is for project developers.  Use -Wno-dev to suppress it.
[cmake] 
[cmake] -- Performing Test cppad_cplusplus_201100_ok
[cmake] -- Performing Test cppad_cplusplus_201100_ok - Success
[cmake] -- cppad_cplusplus_201100_ok = 1
[cmake] -- cmake_install_datadir = share
[cmake] -- cmake_install_docdir = NOTFOUND
[cmake] -- cmake_install_includedirs = include
[cmake] -- cmake_install_libdirs = lib
[cmake] -- cppad_prefix = /usr/local
[cmake] -- cppad_postfix = NOTFOUND
[cmake] -- cppad_cxx_flags = 
[cmake] -- cppad_profile_flag = NOTFOUND
[cmake] -- cppad_testvector = cppad
[cmake] -- cppad_max_num_threads = 48
[cmake] -- cppad_tape_id_type = unsigned int
[cmake] -- cppad_tape_addr_type = unsigned int
[cmake] -- cppad_debug_which = debug_all
[cmake] -- include_eigen = false
[cmake] -- include_adolc = false
[cmake] -- include_ipopt = false
[cmake] -- include_cppadcg = false
[cmake] -- colpack_prefix = NOTFOUND
[cmake] -- sacado_prefix = NOTFOUND
[cmake] -- fadbad_prefix = NOTFOUND
[cmake] -- CMAKE_CXX_FLAGS_DEBUG = -g
[cmake] -- CMAKE_CXX_FLAGS_RELEASE = -O3 -DNDEBUG
[cmake] -- Found OpenMP_C: -fopenmp (found version "4.5") 
[cmake] -- Found OpenMP_CXX: -fopenmp (found version "4.5") 
[cmake] -- Found OpenMP: TRUE (found version "4.5")  
[cmake] -- Found Boost: /usr/lib/x86_64-linux-gnu/cmake/Boost-1.71.0/BoostConfig.cmake (found version "1.71.0") found components: thread 
[cmake] -- boost_prefix = /usr
[cmake] -- Found /usr/include
[cmake] -- Found /usr/lib
[cmake] -- Performing Test compiler_has_conversion_warn
[cmake] -- Performing Test compiler_has_conversion_warn - Success
[cmake] -- compiler_has_conversion_warn = 1
[cmake] -- cppad_boostvector = 0
[cmake] -- cppad_cppadvector = 1
[cmake] -- cppad_eigenvector = 0
[cmake] -- cppad_stdvector = 0
[cmake] -- cppad_cplusplus_201100_ok = 1
[cmake] -- Performing Test cppad_has_gettimeofday
[cmake] -- Performing Test cppad_has_gettimeofday - Success
[cmake] -- cppad_has_gettimeofday = 1
[cmake] -- Performing Test cppad_tape_id_type_is_unsigned
[cmake] -- Performing Test cppad_tape_id_type_is_unsigned - Success
[cmake] -- cppad_tape_id_type_is_unsigned = 1
[cmake] -- Performing Test cppad_tape_addr_type_is_unsigned
[cmake] -- Performing Test cppad_tape_addr_type_is_unsigned - Success
[cmake] -- cppad_tape_addr_type_is_unsigned = 1
[cmake] -- Performing Test cppad_max_num_threads_is_integer_ge_4
[cmake] -- Performing Test cppad_max_num_threads_is_integer_ge_4 - Success
[cmake] -- Performing Test cppad_has_mkstemp
[cmake] -- Performing Test cppad_has_mkstemp - Success
[cmake] -- cppad_has_mkstemp = 1
[cmake] -- Performing Test cppad_has_tmpnam_s
[cmake] -- Performing Test cppad_has_tmpnam_s - Failed
[cmake] -- cppad_has_tmpnam_s = 0
[cmake] -- soversion = 712.8
[cmake] -- Not Windows system so building shared cppad_lib
[cmake] -- make check_example_abs_normal: available
[cmake] -- make check_example_atomic_two: available
[cmake] -- make check_example_atomic_three: available
[cmake] -- make check_example_chkpoint_two: available
[cmake] -- make check_example_graph: available
[cmake] -- make check_example_general: available
[cmake] -- make check_example_get_started: available
[cmake] -- make check_example_json: available
[cmake] -- make check_example_multi_thread_openmp: available
[cmake] -- pthread library path = /usr/lib/x86_64-linux-gnu/libpthread.so
[cmake] -- Looking for pthread_barrier_wait in pthread
[cmake] -- Looking for pthread_barrier_wait in pthread - found
[cmake] -- make check_example_multi_thread_pthread: available
[cmake] -- Performing Test boost_multi_thread_ok
[cmake] -- Performing Test boost_multi_thread_ok - Success
[cmake] -- make check_example_multi_thread_bthread: available
[cmake] -- make check_example_multi_thread: available
[cmake] -- make check_example_optimize: available
[cmake] -- make check_example_print_for: available
[cmake] -- make check_example_sparse: available
[cmake] -- make check_example_utility: available
[cmake] -- make check_example: available
[cmake] -- make check_introduction: available
[cmake] -- make check_test_more_deprecated_atomic_two: available
[cmake] -- make check_test_more_deprecated_chkpoint_one: available
[cmake] -- make check_test_more_deprecated: available
[cmake] -- make check_det_by_minor_c: available
[cmake] -- make check_det_by_minor_cpp: available
[cmake] -- make check_test_more_compare_c: available
[cmake] -- make check_test_more_debug_rel: available
[cmake] -- make check_test_more_cppad_for_tmb: available
[cmake] -- make check_test_more_general: available
[cmake] -- make check_test_more: available
[cmake] -- make check_speed_cppad: available
[cmake] -- make check_speed_double: available
[cmake] -- make check_speed_example: available
[cmake] -- make check_speed_program: available
[cmake] -- make check_speed_xpackage: available
[cmake] -- make check_speed: available
[cmake] -- make check: avialable
[cmake] CMake Error at build/_deps/cppad-src/CMakeLists.txt:452 (ADD_CUSTOM_TARGET):
[cmake]   ADD_CUSTOM_TARGET cannot create target "uninstall" because another target
[cmake]   with the same name already exists.  The existing target is a custom target
[cmake]   created in source directory
[cmake]   "project/build/_deps/eigen-src".  See documentation for
[cmake]   policy CMP0002 for more details.
[cmake] 
[cmake] 
[cmake] -- Fetching cppadcodgen...
[cmake] CMake Deprecation Warning at build/_deps/cppadcodgen-src/CMakeLists.txt:18 (CMAKE_MINIMUM_REQUIRED):
[cmake]   Compatibility with CMake < 2.8.12 will be removed from a future version of
[cmake]   CMake.
[cmake] 
[cmake]   Update the VERSION argument <min> value or use a ...<max> suffix to tell
[cmake]   CMake that the project does not need compatibility with older versions.
[cmake] 
[cmake] 
[cmake] CMake Warning (dev) at build/_deps/cppadcodgen-src/CMakeLists.txt:20 (PROJECT):
[cmake]   Policy CMP0048 is not set: project() command manages VERSION variables.
[cmake]   Run "cmake --help-policy CMP0048" for policy details.  Use the cmake_policy
[cmake]   command to set the policy and suppress this warning.
[cmake] 
[cmake]   The following variable(s) would be set to empty:
[cmake] 
[cmake]     PROJECT_VERSION
[cmake]     PROJECT_VERSION_MAJOR
[cmake]     PROJECT_VERSION_MINOR
[cmake]     PROJECT_VERSION_PATCH
[cmake] This warning is for project developers.  Use -Wno-dev to suppress it.
[cmake] 
[cmake] -- Found PkgConfig: /usr/bin/pkg-config (found version "0.29.1") 
[cmake] -- Found CppAD: project/build/_deps/cppad-src/include (Required is at least version "20200000.1") 
[cmake] CMake Error at build/_deps/cppadcodgen-src/cmake/FindCppAD.cmake:86 (FILE):
[cmake]   FILE STRINGS file
[cmake]   "project/build/_deps/cppadcodgen-src/CPPAD_INCLUDE_DIR-NOTFOUND/cppad/configure.hpp"
[cmake]   cannot be read.
[cmake] Call Stack (most recent call first):
[cmake]   build/_deps/cppadcodgen-src/CMakeLists.txt:42 (FIND_PACKAGE)
[cmake] 
[cmake] 
[cmake] CMake Error at build/_deps/cppadcodgen-src/cmake/FindCppAD.cmake:99 (MESSAGE):
[cmake]   Found CppAD version '' but at least version '20200000.1' is required
[cmake] Call Stack (most recent call first):
[cmake]   build/_deps/cppadcodgen-src/CMakeLists.txt:42 (FIND_PACKAGE)
[cmake] 
[cmake] 
[cmake] -- Configuring incomplete, errors occurred!

有人能在他们的机器上实现上述目标吗?如果是,他们会分享他们是如何做到的吗? 在上面的错误消息中有几个错误,我已经尝试了一些解决方案,但是 none 其中有效 - 我不会列出他们,因为他们提了也没用!

编辑

@dlivshen 当我将我的库与一个更大的项目集成时,由于目标名称冲突,我遇到了更多问题。这是因为我用FetchContent得到了Eigen。所以我决定使用 ExternalProject 获取它,为此我将这些行添加到您在解决方案中提出的 CMakeLists.txt.in 文件中:

ExternalProject_Add(
  eigen
  GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
  GIT_TAG 3.4.0
  GIT_SHALLOW TRUE
  GIT_PROGRESS TRUE
  CMAKE_CACHE_ARGS
    -DCMAKE_INSTALL_PREFIX:STRING=${CMAKE_BINARY_DIR}/eigen
    -DEIGEN_BUILD_DOC
    OFF
    -DBUILD_TESTING
    OFF
    -DEIGEN_LEAVE_TEST_IN_ALL_TARGET
    OFF
    -DEIGEN_BUILD_PKGCONFIG
    OFF)

然后,为了使用 Eigen,我必须将 ${CMAKE_BINARY_DIR}/eigen/include/eigen3 添加到 target_include_directories 命令中。这与我使用 FetchContent 时形成对比,我只需要将 Eigen3::Eigen 添加到 target_link_libraries 命令。 这种方法不适用于 ExternalProject:这个说法正确吗?如果没有,我该如何实现?

问题概述

如您提供的输出所示,存在 2 个问题:

  1. 可能 CppADeigen 之间存在目标名称冲突。他们都有 uninstall 目标。可以在这里看到:
[cmake] CMake Error at build/_deps/cppad-src/CMakeLists.txt:452 (ADD_CUSTOM_TARGET):
[cmake]   ADD_CUSTOM_TARGET cannot create target "uninstall" because another target
[cmake]   with the same name already exists.  The existing target is a custom target
[cmake]   created in source directory
[cmake]   "project/build/_deps/eigen-src".  
  1. cppadcodgen 需要已安装的 CppAD 版本。可以在告诉我们发现无效版本的错误消息中看到:
[cmake] CMake Error at build/_deps/cppadcodgen-src/cmake/FindCppAD.cmake:99 (MESSAGE):
[cmake]   Found CppAD version '' but at least version '20200000.1' is required
[cmake] Call Stack (most recent call first):
[cmake]   build/_deps/cppadcodgen-src/CMakeLists.txt:42 (FIND_PACKAGE)

解决方案

很遗憾,目前我们无法使用 FetchContent 来处理这些问题,因为:

  1. 没有任何机制可以让我们区分相互冲突的目标(例如,“命名空间”前缀可能是一个解决方案,然后可能有 2 个目标 eigen:uninstallcppad:uninstall)。
  2. 我们无法在配置步骤中构建依赖目标。

我们将使用 ExternalProject 模块。这是一个可能的解决方案:

include(FetchContent)

message(STATUS "Fetching eigen...")
FetchContent_Declare(
  eigen
  GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
  GIT_TAG 3.4.0
  GIT_SHALLOW TRUE
  GIT_PROGRESS TRUE)
option(EIGEN_BUILD_DOC OFF)
option(BUILD_TESTING OFF)
option(EIGEN_LEAVE_TEST_IN_ALL_TARGET OFF)
option(EIGEN_BUILD_PKGCONFIG OFF)
FetchContent_MakeAvailable(eigen)

include(ExternalProject)
ExternalProject_Add(cppad
  GIT_REPOSITORY    https://github.com/coin-or/CppAD.git
  GIT_TAG           20210000.8
  GIT_SHALLOW TRUE
  GIT_PROGRESS TRUE
  CMAKE_CACHE_ARGS -Dcppad_prefix:STRING=${CMAKE_BINARY_DIR}/cppad
)

ExternalProject_Add(cppadcodgen
  GIT_REPOSITORY    https://github.com/joaoleal/CppADCodeGen.git
  GIT_TAG           v2.4.3
  GIT_SHALLOW TRUE
  GIT_PROGRESS TRUE
  CMAKE_CACHE_ARGS -DCPPAD_HOME:STRING=${CMAKE_BINARY_DIR}/cppad/include -DGOOGLETEST_GIT:BOOL=ON -DCMAKE_INSTALL_PREFIX:STRING=${CMAKE_BINARY_DIR}/cppadcodegen
  DEPENDS cppad
)

我使用以下命令对其进行测试:

mkdir cmake-build
cd !$
cmake ..
cmake --build .

说明

大部分参数与FetchContent中使用的完全相同。唯一的区别是:

  • 我们将 cppad 安装到构建目录而不是系统目录,因此整个过程将是独立的。它是通过在 CMAKE_CACHE_ARGS 选项中将 cppad_prefix 缓存变量设置为 ${CMAKE_BINARY_DIR}/cppad 来实现的。

  • 我们通过将 CPPAD_HOME 缓存变量设置为包含目录(即 ${CMAKE_BINARY_DIR}/cppad/include)来确保 cppadcodgen 成功找到 CppAD,并且在使用 DEPENDS 选项安装 CppAD 之后,还将此目标设置为 运行。

  • cppadcodgen 也设置了测试目标,如果找不到 Google 测试就会失败。幸运的是,他们提供了一个选项,可以使用我们设置为 ON.

    GOOGLETEST_GIT 选项下载 Google 测试
  • 最后,我们通过设置 CMAKE_INSTALL_PREFIX 变量来设置在构建目录中安装 cppadcodgen

请注意,我没有触及 eigen,因为我不知道确切的用法是什么,而且它没有使构建失败。如果需要,可以很容易地将其修改为 ExternalProject,如上所述。

有关 ExternalProject 的更多信息可以在 Cmake 的 documentation 中找到。

使用依赖项

为了使用依赖项,我们必须执行一些修改。 让我们以来自 CppADCodeGen wiki page 的主文件为例,并尝试用我们的解决方案编译它:

main.cpp

#include <iosfwd>
#include <vector>
#include <cppad/cg.hpp>

using namespace CppAD;
using namespace CppAD::cg;

int main() {
    // use a special object for source code generation
    typedef CG<double> CGD;
    typedef AD<CGD> ADCG;

    /***************************************************************************
     *                               the model
     **************************************************************************/

    // independent variable vector
    CppAD::vector<ADCG> x(2);
    x[0] = 2.;
    x[1] = 3.;
    Independent(x);

    // dependent variable vector 
    CppAD::vector<ADCG> y(1);

    // the model
    ADCG a = x[0] / 1. + x[1] * x[1];
    y[0] = a / 2;

    ADFun<CGD> fun(x, y); // the model tape

    /***************************************************************************
     *                        Generate the C source code
     **************************************************************************/

    /**
     * start the special steps for source code generation for a Jacobian
     */
    CodeHandler<double> handler;

    CppAD::vector<CGD> indVars(2);
    handler.makeVariables(indVars);

    CppAD::vector<CGD> jac = fun.SparseJacobian(indVars);

    LanguageC<double> langC("double");
    LangCDefaultVariableNameGenerator<double> nameGen;

    std::ostringstream code;
    handler.generateCode(code, langC, jac, nameGen);
    std::cout << code.str();
}

请注意 ExternalProject_Add 命令 运行 在构建时执行,我们希望在 Cmake 重新加载期间找到我们的依赖项。所以不幸的是,我们将不得不做一个卑鄙的把戏,在 Cmake 重新加载时强制 ExternalProject_Add 到 运行:

  1. 我们会将 ExternalProject_Add 命令移动到帮助程序 CMakeLists.txt.in 文件中。
  2. 我们将配置 CMakeLists.txt.in 以便库的输出路径将保留在我们的构建目录中。
  3. 我们将调用 execute_process(在 cmake 重新加载时 运行)来执行助手 CMakeLists.txt.in
  4. 的构建过程
  5. 我们将找到我们的库并使用它们。请注意,我们不能使用现代 Cmake 目标语法,因为整个过程在子过程中 运行 并且我们无权访问创建的目标。但是即使我们没有在子进程中 运行 它,ExternalProject 目标的类型是实用程序,不能在 target_link_libraries 等命令中使用。因此,我们将使用我们为依赖项创建的自定义路径并将它们传递给 target_link_librariestarget_include_directories 命令。

最终结果显示如下:

CMakeLists.txt.in

cmake_minimum_required(VERSION 2.8)

project(deps-download NONE)

include(ExternalProject)
ExternalProject_Add(cppad
  GIT_REPOSITORY    https://github.com/coin-or/CppAD.git
  GIT_TAG           20210000.8
  GIT_SHALLOW TRUE
  GIT_PROGRESS TRUE
  CMAKE_CACHE_ARGS -Dcppad_prefix:STRING=${CMAKE_BINARY_DIR}/cppad
)

ExternalProject_Add(cppadcodgen
  GIT_REPOSITORY    https://github.com/joaoleal/CppADCodeGen.git
  GIT_TAG           v2.4.3
  GIT_SHALLOW TRUE
  GIT_PROGRESS TRUE
  CMAKE_CACHE_ARGS -DCPPAD_HOME:STRING=${CMAKE_BINARY_DIR}/cppad/include -DGOOGLETEST_GIT:BOOL=ON -DCMAKE_INSTALL_PREFIX:STRING=${CMAKE_BINARY_DIR}/cppadcodegen
  DEPENDS cppad
)

CMakeLists.txt

include(FetchContent)

message(STATUS "Fetching eigen...")
FetchContent_Declare(
  eigen
  GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
  GIT_TAG 3.4.0
  GIT_SHALLOW TRUE
  GIT_PROGRESS TRUE)
option(EIGEN_BUILD_DOC OFF)
option(BUILD_TESTING OFF)
option(EIGEN_LEAVE_TEST_IN_ALL_TARGET OFF)
option(EIGEN_BUILD_PKGCONFIG OFF)
FetchContent_MakeAvailable(eigen)

# Configure the helper CMakeLists with the dependencies
configure_file(CMakeLists.txt.in ${CMAKE_BINARY_DIR}/deps-build/CMakeLists.txt)

# Build it
execute_process(COMMAND ${CMAKE_COMMAND} .
        WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/deps-build)

execute_process(COMMAND ${CMAKE_COMMAND} --build .
        WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/deps-build)       

# Find cppad_lib's path
find_library(cppad_lib cppad_lib HINTS ${CMAKE_BINARY_DIR}/cppad/lib REQUIRED)
      
# Create our target
add_executable(main
    main.cpp)
    
target_link_libraries(main ${cppad_lib})
target_include_directories(main PUBLIC 
    ${CMAKE_BINARY_DIR}/cppad/include
    ${CMAKE_BINARY_DIR}/cppadcodegen/include)

和以前一样,我使用以下命令对其进行测试:

mkdir cmake-build
cd !$
cmake ..
cmake --build .
./main

解决方案基于this post.