gpt4 book ai didi

cmake - 将ExternalProject 下载步骤与Ninja 一起使用

转载 作者:行者123 更新时间:2023-12-01 22:18:49 24 4
gpt4 key购买 nike

这似乎是一个没有明确答案的常见问题。

情况是:我们有一个第三方依赖项,我们希望在构建依赖于它的目标时在构建时安装它。大致是:

ExternalProject_Add(target-ep
DOWNLOAD_COMMAND <whatever>
BUILD_COMMAND ""
INSTALL_COMMAND ""
CONFIGURE_COMMAND "")

add_library(target-imp STATIC IMPORTED)
set_target_properties(target-imp PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES /path/to/install/include
IMPORTED_LOCATION /path/to/install/lib/libwhatever.a)

add_library(target INTERFACE)
target_link_libraries(target INTERFACE target-imp)
add_dependencies(target target-ep)

(这里需要三个人才能跳探戈,因为 cmake issue 15052 )

当使用 Unix Makefiles 作为生成器时,这非常有效。仅按需安装依赖项,所有构建都能正常工作。

但是,在 Ninja 上,此操作会立即失败,并显示以下内容:

ninja: error: '/path/to/install/lib/libwhatever.a', needed by 'something', missing and no known rule to make it

这是因为 Ninja 扫描依赖关系的方式与 Make 不同(请参阅 ninja issue 760 )。所以我们要做的就是告诉 Ninja 这个外部依赖是存在的。我们可以做到:

ExternalProject_Add(target-ep
DOWNLOAD_COMMAND <whatever>
BUILD_BYPRODUCTS /path/to/install/lib/libwhatever.a
BUILD_COMMAND ""
INSTALL_COMMAND ""
CONFIGURE_COMMAND "")

不幸的是,这也失败了:

No build step for 'target-ep'ninja: error: mkdir(/path/to/install): Permission denied

这是因为我的下载步骤有权写入该路径,但是底层 add_custom_command() 正在使用 ExternalProject_Add 运行任何 mkdir 命令() 没有。

所以:

  1. 使用 Ninja 和 CMake 可以实现这一点吗? (版本不是问题,如果可以解决问题我可以使用最新的CMake)
  2. 如果有某种方法可以显式列出 BUILD_BYPRODUCTS,是否有办法简单地表明将要安装的整个目录是副产品?也就是说,/path/to/install/* 是副产品?

最佳答案

隐藏的mkdir步骤ExternalProject (所有其他步骤直接或间接依赖于此)始终尝试创建完整的目录集,即使它们不会被使用。你可以看到这个here 。作为引用,它执行以下操作:

ExternalProject_Add_Step(${name} mkdir
COMMENT "Creating directories for '${name}'"
COMMAND ${CMAKE_COMMAND} -E make_directory ${source_dir}
COMMAND ${CMAKE_COMMAND} -E make_directory ${binary_dir}
COMMAND ${CMAKE_COMMAND} -E make_directory ${install_dir}
COMMAND ${CMAKE_COMMAND} -E make_directory ${tmp_dir}
COMMAND ${CMAKE_COMMAND} -E make_directory ${stamp_dir}${cfgdir}
COMMAND ${CMAKE_COMMAND} -E make_directory ${download_dir}
COMMAND ${CMAKE_COMMAND} -E make_directory ${log_dir} # This one only since CMake 3.13
)

Unix 系统上的默认安装位置可能是 /usr/local ,因此,如果您没有对其尝试创建的所有目录的写入权限,那么这可能与您的问题有关。我建议您检查每个位置的权限,并确保它们已经存在或可写。或者,您可以指定构建树本地的安装目录,这样即使不会使用它,也至少可以始终创建它(请参阅下面的示例)。

如果你使用Ninja,它的依赖性检查会比make更严格。您有target-ep进行提供 libwhatever.a 的下载,所以你确实需要BUILD_BYPRODUCTS告诉 Ninja target-ep是什么创建了该文件。正如您所发现的,如果您不这样做,那么 target-imp会指向一个最初不存在的库,Ninja 正确地提示它丢失了并且不知道如何创建它。如果您提供BUILD_BYPRODUCTS ,构建步骤不应该为空是有道理的,因此您可能需要执行一些操作作为构建步骤,即使它只是 BUILD_COMMAND这实际上并没有做任何有意义的事情。

以下 target-ep 的修改定义应该希望能让事情为你工作:

ExternalProject_Add(target-ep
INSTALL_DIR ${CMAKE_CURRENT_BUILD_DIR}/dummyInstall
DOWNLOAD_COMMAND <whatever>
BUILD_BYPRODUCTS /path/to/install/lib/libwhatever.a
BUILD_COMMAND ${CMAKE_COMMAND} -E echo_append
INSTALL_COMMAND ""
CONFIGURE_COMMAND "")

您原来的问题还创建了对错误目标的依赖。 target-imp应该取决于target-ep ,但你有target取决于target-ep反而。正确的依赖关系可以这样表达:

 add_dependencies(target-imp target-ep)

BUILD_BYPRODUCTS选项,Ninja 已经知道上述依赖关系,但其他生成器(包括 make)需要它。

您还没有指定您的 <whatever> download 命令确实如此,但我假设它负责确保该库存在于 /path/to/install/lib/libwhatever.a当它执行时。您也可以尝试制作DOWNLOAD_COMMAND空并放置<whatever>作为BUILD_COMMAND相反。

解决您的具体问题:

  1. Is this possible at all with Ninja and CMake? (Version is not an issue, I can use the latest CMake if that solves the problem)

是的,我验证了上述方法适用于 Ninja 1.8.2,使用 CMake 3.11.0 在 macOS 上进行虚拟测试项目。我希望它能够与 CMake 3.2 或更高版本一起使用(此时添加了对 BUILD_BYPRODUCTS 选项的支持)。

  1. If there is some way to workaround with explicitly listing BUILD_BYPRODUCTS, is there a way to simply communicate that the entire directory that will get installed is a byproduct? That is, /path/to/install/* is a byproduct?

不太可能。 Ninja 如何知道这样的目录中应该有什么内容?获得可靠依赖关系的唯一方法是显式列出预期存在的每个文件,您可以使用 BUILD_BYPRODUCTS 来执行此操作。在你的情况下。

关于cmake - 将ExternalProject 下载步骤与Ninja 一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50400592/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com