Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support finding package from cmake #1632

Closed
xq114 opened this issue Sep 2, 2021 · 27 comments
Closed

support finding package from cmake #1632

xq114 opened this issue Sep 2, 2021 · 27 comments

Comments

@xq114
Copy link
Contributor

xq114 commented Sep 2, 2021

你在什么场景下需要该功能?

使用cmake的find_package获取外部依赖。一来有些库默认提供cmake,并且是高度自定义的cmake,较难使用xmake package集成;二来一些cmake script可以直接从之前的库copy,无需重写+测试

这项功能meson已经提供 https://mesonbuild.com/Dependencies.html#cmake ,实现的源代码在 https://github.com/mesonbuild/meson/blob/HEAD/mesonbuild/dependencies/cmake.py ,大致思路是用cmake生成一个临时工程,然后解析CMakeCache里生成的flags。

不过xmake中引入cmake的package还不太方便,因为与系统包不同,cmake有组件系统(find_package同时找寻多个组件,最后链接的implib可能是其中某个组件;同时链接可能是${FOO_LIBRARIES}变量也可能是foo::foo target),并且cmake在find_package前往往需要一些preset variables。xmake直接add_requires("cmake::foo")是无法处理这么多因素的,需要设计一下

描述可能的解决方案

add_requires("cmake::Boost", {configs={
    version="1.75",
    include_directories="${Boost_INCLUDE_DIRS}"
    link_libraries="Boost::filesystem Boost::system",
    presets=format("set(Boost_USE_STATIC_LIBS %s)\nset(Boost_USE_STATIC_RUNTIMES %s)",
                   is_kind("static") and "ON" or "OFF",
                   vsruntime:startswith("MT") and "ON" or "OFF")}})

这种方案对内置的cmake package奏效,但在比较复杂的情况下(cmake需要引入一些外部模块),在presets变量中声明外部模块会比较困难。

描述你认为的候选方案

-- filesystem
cmake/FindABC.cmake
xmake/template.cmake
xmake.lua
# template.cmake
add_cmake_modules(${CMAKE_CURRENT_LIST_DIR}/../cmake)
...# (set variables or setting up vcpkg or doing some other operations)
find_package(ABC REQUIRED)
add_library(myproj-ABC ${XMAKE_KIND} ${XMAKE_SOURCES})
target_link_libraries(myproj-ABC ABC::ABC1 ABC::ABC3)
-- xmake.lua
add_requires("cmake::ABC13", {template="xmake/template.cmake", target="myproj-ABC"})
...
add_packages("ABC13")

Related issues: #1086 (comment)

@waruqi
Copy link
Member

waruqi commented Sep 3, 2021

还是走 package() + on_fetch + add_configs + cmake 辅助脚本更好些。。还可以对现有包直接做 fetch 增强。。对上层 add_requires() 也不需要特殊配置什么,用户使用成本更低

毕竟不同包, cmake 提供的 findxxx.cmake 差异很大,放到 package() 里面更能定制化分别处理

而 add_configs 正好也能支持组件式 find 在 on_fetch 里面。。

只需要搞个 import("package.tools.cmake").find_package 的辅助脚本在 on_fetch 里面调用,里面可以做你说的 创建个临时 cmake 工程来提取 包信息,各种定制化参数 和 preset 也可以这里传递。。

毕竟这种定制化传参对用户来说要求和成本过高,而对于包制作者,就无所谓了。

@waruqi
Copy link
Member

waruqi commented Sep 3, 2021

不过这个最近没时间搞,先排着吧

@waruqi waruqi added this to the v2.5.9 milestone Oct 8, 2021
@waruqi
Copy link
Member

waruqi commented Oct 11, 2021

大体搞完了

find_package("cmake::ZLIB")

测试

$ xmake l find_package cmake::ZLIB
{
  links = {
    "z"
  },
  includedirs = {
    "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.
15.sdk/usr/include"
  },
  linkdirs = {
    "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.
15.sdk/usr/lib"
  }
}
$ xmake l find_package cmake::LibXml2
{
  links = {
    "xml2"
  },
  includedirs = {
    "/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/usr/include/libxml2"
  },
  linkdirs = {
    "/usr/lib"
  }
}

指定版本

find_package("cmake::OpenCV", {required_version = "4.1.1"})

指定组件

find_package("cmake::Boost", {components = {"regex", "system"}})

预设开关

find_package("cmake::Boost", {components = {"regex", "system"}, presets = {Boost_USE_STATIC_LIB = true}})
set(Boost_USE_STATIC_LIB ON) -- will be used in FindBoost.cmake
find_package(Boost REQUIRED COMPONENTS regex system)

设置环境变量

find_package("cmake::OpenCV", {envs = {CMAKE_PREFIX_PATH = "xxx"}})

指定自定义 FindFoo.cmake 模块脚本目录

mydir/cmake_modules/FindFoo.cmake

find_package("cmake::Foo", {moduledirs = "mydir/cmake_modules"})

包依赖集成

package("xxx")
    on_fetch(function (package, opt)
         return package:find_package("cmake::xxx", opt)
    end)
package_end()

add_requires("xxx")

包依赖集成(可选组件)

package("boost")
    add_configs("regex",   { description = "Enable regex.", default = false, type = "boolean"})
    on_fetch(function (package, opt)
         opt.components = {}
         if package:config("regex") then
             table.insert(opt.components, "regex")
         end
         return package:find_package("cmake::Boost", opt)
    end)
package_end()

add_requires("boost", {configs = {regex = true}})

@waruqi
Copy link
Member

waruqi commented Oct 11, 2021

不过现在还有一些问题:

有些包 cmake 获取到的 links 是 Boost::regex Boost::system 这种的,不是真实库名,暂时不支持

这个怎么取到真实 lib 名呢? 有些 CMakeCache.txt 都没有这些信息

还有 win 上还没测试,仅仅测试了 macOS/linux, win上可以帮忙测试和改进下

https://github.com/xmake-io/xmake/blob/dev/xmake/modules/package/manager/cmake/find_package.lua

@xq114
Copy link
Contributor Author

xq114 commented Oct 11, 2021

这个接口可以设置preset吗?

@xq114
Copy link
Contributor Author

xq114 commented Oct 11, 2021

meson是建立了一个phony target,然后取这个target的link.txt,而不是单一个find_package语句,后者会找不到真实库名

@waruqi
Copy link
Member

waruqi commented Oct 11, 2021

这个接口可以设置preset吗?

preset 是啥?

@xq114
Copy link
Contributor Author

xq114 commented Oct 11, 2021

preset 是啥?

就上面说的

set(Boost_USE_STATIC_LIB ON) -- will be used in FindBoost.cmake
find_package(Boost REQUIRED COMPONENTS regex filesystem)

这样

@waruqi
Copy link
Member

waruqi commented Oct 11, 2021

meson是建立了一个phony target,然后取这个target的link.txt,而不是单一个find_package语句,后者会找不到真实库名

这种我也想过,主要是想探测快点,搞个 target cmake 还会去额外探测各种编译器环境啥的额,生成工程文件

@xq114
Copy link
Contributor Author

xq114 commented Oct 11, 2021

meson是建立了一个phony target,然后取这个target的link.txt,而不是单一个find_package语句,后者会找不到真实库名

这种我也想过,主要是想探测快点,搞个 target cmake 还会去额外探测各种编译器环境啥的额,生成工程文件

这些总是可以加参数解决的,比如设置find_package("cmake::FOO", {target_kind=binary})这种

@waruqi
Copy link
Member

waruqi commented Oct 11, 2021

set(Boost_USE_STATIC_LIB ON) -- will be used in FindBoost.cmake

哦,各种提前设置的开关哈,有命名要求么。。Boost_xxx格式? 还是随意的?

@waruqi
Copy link
Member

waruqi commented Oct 11, 2021

preset 是啥?

就上面说的

set(Boost_USE_STATIC_LIB ON) -- will be used in FindBoost.cmake
find_package(Boost REQUIRED COMPONENTS regex filesystem)

这样

我加上了

find_package("cmake::Boost", {components = {"regex", "system"}, presets = {USE_STATIC_LIB = true}})

@xq114
Copy link
Contributor Author

xq114 commented Oct 11, 2021

我加上了

find_package("cmake::Boost", {components = {"regex", "system"}, presets = {USE_STATIC_LIB = true}})

哦,各种提前设置的开关哈,有命名要求么。。Boost_xxx格式? 还是随意的?

没有命名要求,是随意的,这里还是用全名好

@waruqi
Copy link
Member

waruqi commented Oct 11, 2021

我加上了

find_package("cmake::Boost", {components = {"regex", "system"}, presets = {USE_STATIC_LIB = true}})

哦,各种提前设置的开关哈,有命名要求么。。Boost_xxx格式? 还是随意的?

没有命名要求,是随意的,这里还是用全名好

改了

@waruqi
Copy link
Member

waruqi commented Oct 11, 2021

meson是建立了一个phony target,然后取这个target的link.txt,而不是单一个find_package语句,后者会找不到真实库名

这种我也想过,主要是想探测快点,搞个 target cmake 还会去额外探测各种编译器环境啥的额,生成工程文件

这些总是可以加参数解决的,比如设置find_package("cmake::FOO", {target_kind=binary})这种

Boost::regex 这种我也支持了,另外 defines 的提取我也加上了。。至少 linux / macos 上应该没啥大问题了。。win 上暂时没测

@waruqi
Copy link
Member

waruqi commented Oct 11, 2021

比如查找 Qt5 的库

$ xmake l find_package cmake::Qt5Widgets
{ 
  linkdirs = { 
    "/usr/lib/x86_64-linux-gnu" 
  },
  defines = { 
    "QT_CORE_LIB",
    "QT_GUI_LIB",
    "QT_NO_DEBUG",
    "QT_WIDGETS_LIB" 
  },
  links = { 
    "Qt5Widgets",
    "Qt5Gui",
    "Qt5Core" 
  },
  libfiles = { 
    "/usr/lib/x86_64-linux-gnu/libQt5Widgets.so",
    "/usr/lib/x86_64-linux-gnu/libQt5Gui.so",
    "/usr/lib/x86_64-linux-gnu/libQt5Core.so" 
  },
  includedirs = { 
    "/usr/include/x86_64-linux-gnu/qt5",
    "/usr/include/x86_64-linux-gnu/qt5/QtWidgets",
    "/usr/include/x86_64-linux-gnu/qt5/QtGui",
    "/usr/include/x86_64-linux-gnu/qt5/QtCore",
    "/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++" 
  } 
}

@xq114
Copy link
Contributor Author

xq114 commented Oct 11, 2021

怎样声明额外的环境变量?OpenCV_ROOT、CMAKE_PREFIX_PATH这些,我看现在的例子都是cmake内置有FindXXX.cmake的类型(zlib、libxml2、boost、qt都是),没有完全通过config查找的例子

@xq114
Copy link
Contributor Author

xq114 commented Oct 11, 2021

另外还应该支持强制使用config查找,不用内置的FindXXX.cmake,对应语句find_package(<package> CONFIG REQUIRED)

@waruqi
Copy link
Member

waruqi commented Oct 11, 2021

另外还应该支持强制使用config查找,不用内置的FindXXX.cmake,对应语句find_package(<package> CONFIG REQUIRED)

CONFIG 是用来干什么的? 强制走自己的 modules 里面的 findXXX.cmake ?那如果设置了 moduledirs 参数,我就默认启用 config 呢?

@waruqi
Copy link
Member

waruqi commented Oct 11, 2021

怎样声明额外的环境变量?OpenCV_ROOT、CMAKE_PREFIX_PATH这些,我看现在的例子都是cmake内置有FindXXX.cmake的类型(zlib、libxml2、boost、qt都是),没有完全通过config查找的例子

走刚的 presets 不行么。。set(OpenCV_ROOT xxx)

@xq114
Copy link
Contributor Author

xq114 commented Oct 11, 2021

另外还应该支持强制使用config查找,不用内置的FindXXX.cmake,对应语句find_package(<package> CONFIG REQUIRED)

CONFIG 是用来干什么的? 强制走自己的 modules 里面的 findXXX.cmake ?那如果设置了 moduledirs 参数,我就默认启用 config 呢?

强制走XXXConfig.cmake/XXX-config.cmake,忽略所有FindXXX.cmake,moduledirs自然也就失效了

@xq114
Copy link
Contributor Author

xq114 commented Oct 11, 2021

怎样声明额外的环境变量?OpenCV_ROOT、CMAKE_PREFIX_PATH这些,我看现在的例子都是cmake内置有FindXXX.cmake的类型(zlib、libxml2、boost、qt都是),没有完全通过config查找的例子

走刚的 presets 不行么。。set(OpenCV_ROOT xxx)

不行,这个是环境变量,不是cmake变量

@waruqi
Copy link
Member

waruqi commented Oct 11, 2021

另外还应该支持强制使用config查找,不用内置的FindXXX.cmake,对应语句find_package(<package> CONFIG REQUIRED)

自己 presets 里面开启这个优先走 config 呢?
https://cmake.org/cmake/help/latest/variable/CMAKE_FIND_PACKAGE_PREFER_CONFIG.html#variable:CMAKE_FIND_PACKAGE_PREFER_CONFIG

@xq114
Copy link
Contributor Author

xq114 commented Oct 11, 2021

另外还应该支持强制使用config查找,不用内置的FindXXX.cmake,对应语句find_package(<package> CONFIG REQUIRED)

自己 presets 里面开启这个优先走 config 呢? cmake.org/cmake/help/latest/variable/CMAKE_FIND_PACKAGE_PREFER_CONFIG.html#variable:CMAKE_FIND_PACKAGE_PREFER_CONFIG

这个也行

@waruqi
Copy link
Member

waruqi commented Oct 11, 2021

怎样声明额外的环境变量?OpenCV_ROOT、CMAKE_PREFIX_PATH这些,我看现在的例子都是cmake内置有FindXXX.cmake的类型(zlib、libxml2、boost、qt都是),没有完全通过config查找的例子

走刚的 presets 不行么。。set(OpenCV_ROOT xxx)

不行,这个是环境变量,不是cmake变量

加上了

find_package("cmake::OpenCV", {envs = {CMAKE_PREFIX_PATH = "xxx"}})

@waruqi
Copy link
Member

waruqi commented Oct 12, 2021

windows 上也支持了,presets 之前有点问题,也修复了

@waruqi waruqi closed this as completed Oct 12, 2021
@waruqi
Copy link
Member

waruqi commented Dec 16, 2021

我改进了下 #1917

直接用 find_package 还是过于底层,对于用户集成包,还是统一走 add_requires 比较好,之前虽然也有直接在
add_requires 中使用 cmake:: 包,但是无法透传 configs ,现在可以了。

add_requires("cmake::ZLIB", {alias = "zlib", system = true})
target("test")
    set_kind("binary")
    add_files("src/*.c")
    add_packages("zlib")
add_requires("cmake::Boost", {system = true, configs = {components = {"regex", "system"},
                                         presets = {Boost_USE_STATIC_LIB = true}})}

更新后的文档见:https://xmake.io/#/zh-cn/package/local_package?id=%e5%9c%a8%e9%a1%b9%e7%9b%ae%e4%b8%ad%e9%9b%86%e6%88%90%e5%8c%85

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants