summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2023-05-03 00:32:19 +0800
committerGitHub <[email protected]>2023-05-03 00:32:19 +0800
commit3382dcb4994ca70c1b3c5ea7bc220ccac8b736a2 (patch)
tree43eb0712243116dc68ce60b3d74d8065de1aec6e
parent3ae0c1af04ae968e1cd39a61685c40725264e4ff (diff)
parent34e986ea513cfc509dd860b2edab6f867d13a1dd (diff)
Merge pull request #3703 from xmake-io/conan
Support conan 2.0
-rw-r--r--CHANGELOG.md2
-rw-r--r--tests/projects/package/conan/xmake.lua4
-rw-r--r--xmake/modules/package/manager/conan/configurations.lua6
-rw-r--r--xmake/modules/package/manager/conan/install_package.lua268
-rw-r--r--xmake/modules/package/manager/conan/v1/install_package.lua287
-rw-r--r--xmake/modules/package/manager/conan/v2/install_package.lua336
-rw-r--r--xmake/scripts/conan/extensions/generators/xmake_generator.py114
7 files changed, 752 insertions, 265 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d4a0300fb..deb5068d5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,7 @@
### New features
* [#3613](https://github.com/xmake-io/xmake/issues/3613): Add `wasm.preloadfiles` configuration for wasm
+* [#3703](https://github.com/xmake-io/xmake/pull/3703): Support for conan 2.0
### Changes
@@ -1578,6 +1579,7 @@
### 新特性
* [#3613](https://github.com/xmake-io/xmake/issues/3613): 添加 `wasm.preloadfiles` 扩展配置
+* [#3703](https://github.com/xmake-io/xmake/pull/3703): 支持 conan 2.0
### 改进
diff --git a/tests/projects/package/conan/xmake.lua b/tests/projects/package/conan/xmake.lua
index 3021fab7c..ecf8c6b60 100644
--- a/tests/projects/package/conan/xmake.lua
+++ b/tests/projects/package/conan/xmake.lua
@@ -1,6 +1,6 @@
add_requires("conan::zlib 1.2.11", {alias = "zlib", debug = true})
-add_requires("conan::openssl 1.1.1g", {alias = "openssl",
- configs = {options = "OpenSSL:shared=True"}})
+add_requires("conan::openssl 1.1.1t", {alias = "openssl",
+ configs = {options = "shared=True"}})
target("test")
set_kind("binary")
diff --git a/xmake/modules/package/manager/conan/configurations.lua b/xmake/modules/package/manager/conan/configurations.lua
index b4ed38fc3..8e03cf9a3 100644
--- a/xmake/modules/package/manager/conan/configurations.lua
+++ b/xmake/modules/package/manager/conan/configurations.lua
@@ -24,10 +24,10 @@ function main()
{
build = {description = "Use it to choose if you want to build from sources.", default = "missing", values = {"all", "never", "missing", "outdated"}},
remote = {description = "Set the conan remote server."},
- options = {description = "Set the options values, e.g. OpenSSL:shared=True"},
- imports = {description = "Set the imports for conan."},
+ options = {description = "Set the options values, e.g. shared=True"},
settings = {description = "Set the build settings for conan."},
- build_requires = {description = "Set the build requires for conan.", default = "xmake_generator/0.1.0@bincrafters/testing"}
+ imports = {description = "Set the imports for conan 1.x, it has been deprecated in conan 2.x."},
+ build_requires = {description = "Set the build requires for conan."}
}
end
diff --git a/xmake/modules/package/manager/conan/install_package.lua b/xmake/modules/package/manager/conan/install_package.lua
index 2a3f8b38f..48e9f132f 100644
--- a/xmake/modules/package/manager/conan/install_package.lua
+++ b/xmake/modules/package/manager/conan/install_package.lua
@@ -21,280 +21,28 @@
-- imports
import("core.base.option")
import("core.base.semver")
-import("core.project.config")
-import("core.tool.toolchain")
-import("core.platform.platform")
import("lib.detect.find_tool")
-import("devel.git")
-import("net.fasturl")
-
--- get build env
-function _conan_get_build_env(name, plat)
- local value = config.get(name)
- if value == nil then
- value = platform.toolconfig(name, plat)
- end
- if value == nil then
- value = platform.tool(name, plat)
- end
- value = table.unique(table.wrap(value))
- if #value > 0 then
- value = table.unwrap(value)
- return value
- end
-end
-
--- get build directory
-function _conan_get_build_directory(name)
- return path.absolute(path.join(config.buildir() or os.tmpdir(), ".conan", name))
-end
-
--- generate conanfile.txt
-function _conan_generate_conanfile(name, configs, opt)
-
- -- trace
- dprint("generate %s ..", path.join(_conan_get_build_directory(name), "conanfile.txt"))
-
- -- get conan options, imports and build_requires
- local options = table.wrap(configs.options)
- local imports = table.wrap(configs.imports)
- local build_requires = table.wrap(configs.build_requires)
-
- -- @see https://docs.conan.io/en/latest/systems_cross_building/cross_building.html
- -- generate it
- local conanfile = io.open("conanfile.txt", "w")
- if conanfile then
- conanfile:print("[generators]")
- conanfile:print("xmake")
- conanfile:print("[requires]")
- local require_version = opt.require_version
- if require_version ~= nil and require_version ~= "latest" then
- conanfile:print("%s/%s", name, require_version)
- else
- conanfile:print("%s", name)
- end
- if #options > 0 then
- conanfile:print("[options]")
- conanfile:print("%s", table.concat(options, "\n"))
- end
- if #imports > 0 then
- conanfile:print("[imports]")
- conanfile:print("%s", table.concat(imports, "\n"))
- end
- if #build_requires > 0 then
- conanfile:print("[build_requires]")
- conanfile:print("%s", table.concat(build_requires, "\n"))
- end
- conanfile:close()
- end
-end
-
--- install xmake generator
-function _conan_install_xmake_generator(conan)
- local xmake_generator_localdir = path.join(config.directory(), "conan", "xmake_generator")
- if not os.isdir(xmake_generator_localdir) then
-
- -- sort main urls
- local mainurls = {"https://github.com/xmake-io/conan-xmake_generator.git",
- "https://gitlab.com/xmake-io/conan-xmake_generator.git",
- "https://gitee.com/xmake-io/conan-xmake_generator.git"}
- fasturl.add(mainurls)
- mainurls = fasturl.sort(mainurls)
-
- -- clone xmake generator repository
- local ok = false
- for _, url in ipairs(mainurls) do
- ok = try { function () git.clone(url, {depth = 1, branch = "0.1.0/testing", outputdir = xmake_generator_localdir}); return true end }
- if ok then
- break
- end
- end
- if ok then
- os.vrunv(conan.program, {"export", xmake_generator_localdir, "bincrafters/testing"})
- end
- end
-end
-- install package
--
--- @param name the package name, e.g. conan::OpenSSL/1.0.2n@conan/stable
+-- @param name the package name, e.g. conan::OpenSSL 1.0.2n
-- @param opt the options, e.g. { verbose = true, mode = "release", plat = , arch = ,
-- configs = {
-- remote = "", build = "all", options = {}, imports = {}, build_requires = {},
-- settings = {"compiler=msvc", "compiler.version=10", "compiler.runtime=MD"}}}
--
--- @return true or false
---
function main(name, opt)
-
- -- get configs
- opt = opt or {}
- local configs = opt.configs or {}
-
- -- find conan
local conan = find_tool("conan", {version = true})
if not conan then
raise("conan not found!")
end
- if conan.version then
- assert(semver.compare(conan.version, "2.0") < 0, "conan %s is not supported, please use conan 1.x", conan.version)
- end
-
- -- get build directory
- local buildir = _conan_get_build_directory(name)
-
- -- clean the build directory
- os.tryrm(buildir)
- if not os.isdir(buildir) then
- os.mkdir(buildir)
- end
-
- -- enter build directory
- local oldir = os.cd(buildir)
-
- -- install xmake generator
- _conan_install_xmake_generator(conan)
-
- -- generate conanfile.txt
- _conan_generate_conanfile(name, configs, opt)
-
- -- install package
- local argv = {"install", "."}
- if configs.build then
- if configs.build == "all" then
- table.insert(argv, "--build")
- else
- table.insert(argv, "--build=" .. configs.build)
- end
- end
-
- -- set platform
- local plats = {macosx = "Macos", windows = "Windows", mingw = "Windows", linux = "Linux", cross = "Linux", iphoneos = "iOS", android = "Android"}
- table.insert(argv, "-s")
- local plat = plats[opt.plat]
- if plat then
- table.insert(argv, "os=" .. plat)
- else
- raise("cannot install package(%s) on platform(%s)!", name, opt.plat)
- end
-
- -- set architecture
- local archs = {x86_64 = "x86_64",
- x64 = "x86_64",
- i386 = "x86",
- x86 = "x86",
- armv7 = "armv7",
- ["armv7-a"] = "armv7", -- for android, deprecated
- ["armeabi"] = "armv7", -- for android, removed in ndk r17
- ["armeabi-v7a"] = "armv7", -- for android
- armv7s = "armv7s", -- for iphoneos
- arm64 = "armv8", -- for iphoneos
- ["arm64-v8a"] = "armv8", -- for android
- mips = "mips",
- mips64 = "mips64"}
- table.insert(argv, "-s")
- local arch = archs[opt.arch]
- if arch then
- table.insert(argv, "arch=" .. arch)
+ if conan.version and semver.compare(conan.version, "2.0.4") >= 0 then -- TODO 2.0.5
+ -- https://github.com/conan-io/conan/issues/13709
+ import("package.manager.conan.v2.install_package")(conan, name, opt)
+ elseif conan.version and semver.compare(conan.version, "2.0.0") < 0 then
+ import("package.manager.conan.v1.install_package")(conan, name, opt)
else
- raise("cannot install package(%s) for arch(%s)!", name, opt.arch)
+ -- conan 2.0.0-2.0.4 does not supported
+ raise("conan %s is not supported, please use conan 1.x", conan.version)
end
-
- -- set build mode
- table.insert(argv, "-s")
- if opt.mode == "debug" then
- table.insert(argv, "build_type=Debug")
- else
- table.insert(argv, "build_type=Release")
- end
-
- -- set compiler settings
- if opt.plat == "windows" then
- local vsvers = {["2022"] = "17",
- ["2019"] = "16",
- ["2017"] = "15",
- ["2015"] = "14",
- ["2013"] = "12",
- ["2012"] = "11",
- ["2010"] = "10",
- ["2008"] = "9",
- ["2005"] = "8"}
- local vs = assert(config.get("vs"), "vs not found!")
- table.insert(argv, "-s")
- table.insert(argv, "compiler=Visual Studio")
- table.insert(argv, "-s")
- table.insert(argv, "compiler.version=" .. assert(vsvers[vs], "unknown msvc version!"))
- if configs.vs_runtime then
- table.insert(argv, "-s")
- table.insert(argv, "compiler.runtime=" .. configs.vs_runtime)
- end
- elseif opt.plat == "iphoneos" then
- local target_minver = nil
- local toolchain_xcode = toolchain.load("xcode", {plat = opt.plat, arch = opt.arch})
- if toolchain_xcode then
- target_minver = toolchain_xcode:config("target_minver")
- end
- if target_minver and tonumber(target_minver) > 10 and (arch == "armv7" or arch == "armv7s" or arch == "x86") then
- target_minver = "10" -- iOS 10 is the maximum deployment target for 32-bit targets
- end
- if target_minver then
- table.insert(argv, "-s")
- table.insert(argv, "os.version=" .. target_minver)
- end
- elseif opt.plat == "android" then
- local ndk_sdkver = config.get("ndk_sdkver")
- if ndk_sdkver then
- table.insert(argv, "-s")
- table.insert(argv, "os.api_level=" .. ndk_sdkver)
- end
- end
-
- -- set custom settings
- for _, setting in ipairs(configs.settings) do
- table.insert(argv, "-s")
- table.insert(argv, setting)
- end
-
- -- set remote
- if configs.remote then
- table.insert(argv, "-r")
- table.insert(argv, configs.remote)
- end
-
- -- TODO set environments
- if opt.plat == "android" then
- local envs = {}
- local cflags = table.join(table.wrap(_conan_get_build_env("cxflags", opt.plat)), _conan_get_build_env("cflags", opt.plat))
- local cxxflags = table.join(table.wrap(_conan_get_build_env("cxflags", opt.plat)), _conan_get_build_env("cxxflags", opt.plat))
- envs.CC = _conan_get_build_env("cc", opt.plat)
- envs.CXX = _conan_get_build_env("cxx", opt.plat)
- envs.AS = _conan_get_build_env("as", opt.plat)
- envs.AR = _conan_get_build_env("ar", opt.plat)
- envs.LD = _conan_get_build_env("ld", opt.plat)
- envs.LDSHARED = _conan_get_build_env("sh", opt.plat)
- envs.CPP = _conan_get_build_env("cpp", opt.plat)
- envs.RANLIB = _conan_get_build_env("ranlib", opt.plat)
- envs.CFLAGS = table.concat(cflags, ' ')
- envs.CXXFLAGS = table.concat(cxxflags, ' ')
- envs.ASFLAGS = table.concat(table.wrap(_conan_get_build_env("asflags", opt.plat)), ' ')
- envs.ARFLAGS = table.concat(table.wrap(_conan_get_build_env("arflags", opt.plat)), ' ')
- envs.LDFLAGS = table.concat(table.wrap(_conan_get_build_env("ldflags", opt.plat)), ' ')
- envs.SHFLAGS = table.concat(table.wrap(_conan_get_build_env("shflags", opt.plat)), ' ')
- local toolchain_ndk = toolchain.load("ndk", {plat = opt.plat, arch = opt.arch})
- local ndk_sysroot = toolchain_ndk:config("ndk_sysroot")
- if ndk_sysroot then
- table.insert(argv, "-e")
- table.insert(argv, "CONAN_CMAKE_FIND_ROOT_PATH=" .. ndk_sysroot)
- end
- for k, v in pairs(envs) do
- table.insert(argv, "-e")
- table.insert(argv, k .. "=" .. v)
- end
- end
-
- -- do install
- os.vrunv(conan.program, argv)
-
- -- leave build directory
- os.cd(oldir)
end
diff --git a/xmake/modules/package/manager/conan/v1/install_package.lua b/xmake/modules/package/manager/conan/v1/install_package.lua
new file mode 100644
index 000000000..e443e585b
--- /dev/null
+++ b/xmake/modules/package/manager/conan/v1/install_package.lua
@@ -0,0 +1,287 @@
+--!A cross-platform build utility based on Lua
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- Copyright (C) 2015-present, TBOOX Open Source Group.
+--
+-- @author ruki
+-- @file install_package.lua
+--
+
+-- imports
+import("core.base.option")
+import("core.base.semver")
+import("core.project.config")
+import("core.tool.toolchain")
+import("core.platform.platform")
+import("lib.detect.find_tool")
+import("devel.git")
+import("net.fasturl")
+
+-- get build env
+function _conan_get_build_env(name, plat)
+ local value = config.get(name)
+ if value == nil then
+ value = platform.toolconfig(name, plat)
+ end
+ if value == nil then
+ value = platform.tool(name, plat)
+ end
+ value = table.unique(table.wrap(value))
+ if #value > 0 then
+ value = table.unwrap(value)
+ return value
+ end
+end
+
+-- get build directory
+function _conan_get_build_directory(name)
+ return path.absolute(path.join(config.buildir() or os.tmpdir(), ".conan", name))
+end
+
+-- generate conanfile.txt
+function _conan_generate_conanfile(name, configs, opt)
+
+ -- trace
+ dprint("generate %s ..", path.join(_conan_get_build_directory(name), "conanfile.txt"))
+
+ -- get conan options, imports and build_requires
+ local options = table.wrap(configs.options)
+ local imports = table.wrap(configs.imports)
+ local build_requires = table.wrap(configs.build_requires or "xmake_generator/0.1.0@bincrafters/testing")
+
+ -- @see https://docs.conan.io/en/latest/systems_cross_building/cross_building.html
+ -- generate it
+ local conanfile = io.open("conanfile.txt", "w")
+ if conanfile then
+ conanfile:print("[generators]")
+ conanfile:print("xmake")
+ conanfile:print("[requires]")
+ local require_version = opt.require_version
+ if require_version ~= nil and require_version ~= "latest" then
+ conanfile:print("%s/%s", name, require_version)
+ else
+ conanfile:print("%s", name)
+ end
+ if #options > 0 then
+ conanfile:print("[options]")
+ for _, item in ipairs(options) do
+ if not item:find(":", 1, true) then
+ item = name .. ":" .. item
+ end
+ conanfile:print("%s", item)
+ end
+ end
+ if #imports > 0 then
+ conanfile:print("[imports]")
+ conanfile:print("%s", table.concat(imports, "\n"))
+ end
+ if #build_requires > 0 then
+ conanfile:print("[build_requires]")
+ conanfile:print("%s", table.concat(build_requires, "\n"))
+ end
+ conanfile:close()
+ end
+end
+
+-- install xmake generator
+function _conan_install_xmake_generator(conan)
+ local xmake_generator_localdir = path.join(config.directory(), "conan", "xmake_generator")
+ if not os.isdir(xmake_generator_localdir) then
+
+ -- sort main urls
+ local mainurls = {"https://github.com/xmake-io/conan-xmake_generator.git",
+ "https://gitlab.com/xmake-io/conan-xmake_generator.git",
+ "https://gitee.com/xmake-io/conan-xmake_generator.git"}
+ fasturl.add(mainurls)
+ mainurls = fasturl.sort(mainurls)
+
+ -- clone xmake generator repository
+ local ok = false
+ for _, url in ipairs(mainurls) do
+ ok = try { function () git.clone(url, {depth = 1, branch = "0.1.0/testing", outputdir = xmake_generator_localdir}); return true end }
+ if ok then
+ break
+ end
+ end
+ if ok then
+ os.vrunv(conan.program, {"export", xmake_generator_localdir, "bincrafters/testing"})
+ end
+ end
+end
+
+-- install package
+function main(conan, name, opt)
+
+ -- get configs
+ opt = opt or {}
+ local configs = opt.configs or {}
+
+ -- get build directory
+ local buildir = _conan_get_build_directory(name)
+
+ -- clean the build directory
+ os.tryrm(buildir)
+ if not os.isdir(buildir) then
+ os.mkdir(buildir)
+ end
+
+ -- enter build directory
+ local oldir = os.cd(buildir)
+
+ -- install xmake generator
+ _conan_install_xmake_generator(conan)
+
+ -- generate conanfile.txt
+ _conan_generate_conanfile(name, configs, opt)
+
+ -- install package
+ local argv = {"install", "."}
+ if configs.build then
+ if configs.build == "all" then
+ table.insert(argv, "--build")
+ else
+ table.insert(argv, "--build=" .. configs.build)
+ end
+ end
+
+ -- set platform
+ local plats = {macosx = "Macos", windows = "Windows", mingw = "Windows", linux = "Linux", cross = "Linux", iphoneos = "iOS", android = "Android"}
+ table.insert(argv, "-s")
+ local plat = plats[opt.plat]
+ if plat then
+ table.insert(argv, "os=" .. plat)
+ else
+ raise("cannot install package(%s) on platform(%s)!", name, opt.plat)
+ end
+
+ -- set architecture
+ local archs = {x86_64 = "x86_64",
+ x64 = "x86_64",
+ i386 = "x86",
+ x86 = "x86",
+ armv7 = "armv7",
+ ["armv7-a"] = "armv7", -- for android, deprecated
+ ["armeabi"] = "armv7", -- for android, removed in ndk r17
+ ["armeabi-v7a"] = "armv7", -- for android
+ armv7s = "armv7s", -- for iphoneos
+ arm64 = "armv8", -- for iphoneos
+ ["arm64-v8a"] = "armv8", -- for android
+ mips = "mips",
+ mips64 = "mips64"}
+ table.insert(argv, "-s")
+ local arch = archs[opt.arch]
+ if arch then
+ table.insert(argv, "arch=" .. arch)
+ else
+ raise("cannot install package(%s) for arch(%s)!", name, opt.arch)
+ end
+
+ -- set build mode
+ table.insert(argv, "-s")
+ if opt.mode == "debug" then
+ table.insert(argv, "build_type=Debug")
+ else
+ table.insert(argv, "build_type=Release")
+ end
+
+ -- set compiler settings
+ if opt.plat == "windows" then
+ local vsvers = {["2022"] = "17",
+ ["2019"] = "16",
+ ["2017"] = "15",
+ ["2015"] = "14",
+ ["2013"] = "12",
+ ["2012"] = "11",
+ ["2010"] = "10",
+ ["2008"] = "9",
+ ["2005"] = "8"}
+ local vs = assert(config.get("vs"), "vs not found!")
+ table.insert(argv, "-s")
+ table.insert(argv, "compiler=Visual Studio")
+ table.insert(argv, "-s")
+ table.insert(argv, "compiler.version=" .. assert(vsvers[vs], "unknown msvc version!"))
+ if configs.vs_runtime then
+ table.insert(argv, "-s")
+ table.insert(argv, "compiler.runtime=" .. configs.vs_runtime)
+ end
+ elseif opt.plat == "iphoneos" then
+ local target_minver = nil
+ local toolchain_xcode = toolchain.load("xcode", {plat = opt.plat, arch = opt.arch})
+ if toolchain_xcode then
+ target_minver = toolchain_xcode:config("target_minver")
+ end
+ if target_minver and tonumber(target_minver) > 10 and (arch == "armv7" or arch == "armv7s" or arch == "x86") then
+ target_minver = "10" -- iOS 10 is the maximum deployment target for 32-bit targets
+ end
+ if target_minver then
+ table.insert(argv, "-s")
+ table.insert(argv, "os.version=" .. target_minver)
+ end
+ elseif opt.plat == "android" then
+ local ndk_sdkver = config.get("ndk_sdkver")
+ if ndk_sdkver then
+ table.insert(argv, "-s")
+ table.insert(argv, "os.api_level=" .. ndk_sdkver)
+ end
+ end
+
+ -- set custom settings
+ for _, setting in ipairs(configs.settings) do
+ table.insert(argv, "-s")
+ table.insert(argv, setting)
+ end
+
+ -- set remote
+ if configs.remote then
+ table.insert(argv, "-r")
+ table.insert(argv, configs.remote)
+ end
+
+ -- TODO set environments
+ if opt.plat == "android" then
+ local envs = {}
+ local cflags = table.join(table.wrap(_conan_get_build_env("cxflags", opt.plat)), _conan_get_build_env("cflags", opt.plat))
+ local cxxflags = table.join(table.wrap(_conan_get_build_env("cxflags", opt.plat)), _conan_get_build_env("cxxflags", opt.plat))
+ envs.CC = _conan_get_build_env("cc", opt.plat)
+ envs.CXX = _conan_get_build_env("cxx", opt.plat)
+ envs.AS = _conan_get_build_env("as", opt.plat)
+ envs.AR = _conan_get_build_env("ar", opt.plat)
+ envs.LD = _conan_get_build_env("ld", opt.plat)
+ envs.LDSHARED = _conan_get_build_env("sh", opt.plat)
+ envs.CPP = _conan_get_build_env("cpp", opt.plat)
+ envs.RANLIB = _conan_get_build_env("ranlib", opt.plat)
+ envs.CFLAGS = table.concat(cflags, ' ')
+ envs.CXXFLAGS = table.concat(cxxflags, ' ')
+ envs.ASFLAGS = table.concat(table.wrap(_conan_get_build_env("asflags", opt.plat)), ' ')
+ envs.ARFLAGS = table.concat(table.wrap(_conan_get_build_env("arflags", opt.plat)), ' ')
+ envs.LDFLAGS = table.concat(table.wrap(_conan_get_build_env("ldflags", opt.plat)), ' ')
+ envs.SHFLAGS = table.concat(table.wrap(_conan_get_build_env("shflags", opt.plat)), ' ')
+ local toolchain_ndk = toolchain.load("ndk", {plat = opt.plat, arch = opt.arch})
+ local ndk_sysroot = toolchain_ndk:config("ndk_sysroot")
+ if ndk_sysroot then
+ table.insert(argv, "-e")
+ table.insert(argv, "CONAN_CMAKE_FIND_ROOT_PATH=" .. ndk_sysroot)
+ end
+ for k, v in pairs(envs) do
+ table.insert(argv, "-e")
+ table.insert(argv, k .. "=" .. v)
+ end
+ end
+
+ -- do install
+ os.vrunv(conan.program, argv)
+
+ -- leave build directory
+ os.cd(oldir)
+end
diff --git a/xmake/modules/package/manager/conan/v2/install_package.lua b/xmake/modules/package/manager/conan/v2/install_package.lua
new file mode 100644
index 000000000..af2ec771c
--- /dev/null
+++ b/xmake/modules/package/manager/conan/v2/install_package.lua
@@ -0,0 +1,336 @@
+--!A cross-platform build utility based on Lua
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- Copyright (C) 2015-present, TBOOX Open Source Group.
+--
+-- @author ruki
+-- @file install_package.lua
+--
+
+-- imports
+import("core.base.option")
+import("core.base.semver")
+import("core.project.config")
+import("core.tool.toolchain")
+import("core.platform.platform")
+import("lib.detect.find_tool")
+import("devel.git")
+import("net.fasturl")
+
+-- get build env
+function _conan_get_build_env(name, plat)
+ local value = config.get(name)
+ if value == nil then
+ value = platform.toolconfig(name, plat)
+ end
+ if value == nil then
+ value = platform.tool(name, plat)
+ end
+ value = table.unique(table.wrap(value))
+ if #value > 0 then
+ value = table.unwrap(value)
+ return value
+ end
+end
+
+-- get build directory
+function _conan_get_build_directory(name)
+ return path.absolute(path.join(config.buildir() or os.tmpdir(), ".conan", name))
+end
+
+-- generate conanfile.txt
+function _conan_generate_conanfile(name, configs, opt)
+
+ -- trace
+ dprint("generate %s ..", path.join(_conan_get_build_directory(name), "conanfile.txt"))
+
+ -- get conan options, imports and build_requires
+ local options = table.wrap(configs.options)
+ local build_requires = table.wrap(configs.build_requires)
+
+ -- @see https://docs.conan.io/1/migrating_to_2.0/recipes.html
+ -- https://docs.conan.io/en/latest/systems_cross_building/cross_building.html
+ -- generate it
+ local conanfile = io.open("conanfile.txt", "w")
+ if conanfile then
+ conanfile:print("[requires]")
+ local require_version = opt.require_version
+ if require_version ~= nil and require_version ~= "latest" then
+ conanfile:print("%s/%s", name, require_version)
+ else
+ conanfile:print("%s", name)
+ end
+ if #options > 0 then
+ conanfile:print("[options]")
+ for _, item in ipairs(options) do
+ if not item:find(":", 1, true) then
+ item = name .. "/*:" .. item
+ end
+ conanfile:print("%s", item)
+ end
+ end
+ if #build_requires > 0 then
+ conanfile:print("[tool_requires]")
+ conanfile:print("%s", table.concat(build_requires, "\n"))
+ end
+ conanfile:close()
+ end
+end
+
+-- get conan home directory
+function _conan_get_homedir(conan)
+ local homedir = _g.homedir
+ if homedir == nil then
+ homedir = try {function () return os.iorunv(conan.program, {"config", "home"}) end}
+ _g.homedir = homedir
+ end
+ return homedir
+end
+
+-- install xmake generator
+-- @see https://github.com/conan-io/conan/pull/13718
+--
+function _conan_install_xmake_generator(conan)
+ local homedir = assert(_conan_get_homedir(conan), "cannot get conan home")
+ local scriptfile_now = path.join(os.programdir(), "scripts", "conan", "extensions", "generators", "xmake_generator.py")
+ local scriptfile_installed = path.join(homedir, "extensions", "generators", "xmake_generator.py")
+ if not os.isfile(scriptfile_installed) or os.mtime(scriptfile_now) > os.mtime(scriptfile_installed) then
+ os.vrunv(conan.program, {"config", "install", path.join(os.programdir(), "scripts", "conan")})
+ end
+end
+
+-- get arch
+function _conan_get_arch(arch)
+ local map = {x86_64 = "x86_64",
+ x64 = "x86_64",
+ i386 = "x86",
+ x86 = "x86",
+ armv7 = "armv7",
+ ["armv7-a"] = "armv7", -- for android, deprecated
+ ["armeabi"] = "armv7", -- for android, removed in ndk r17
+ ["armeabi-v7a"] = "armv7", -- for android
+ armv7s = "armv7s", -- for iphoneos
+ arm64 = "armv8", -- for iphoneos
+ ["arm64-v8a"] = "armv8", -- for android
+ mips = "mips",
+ mips64 = "mips64"}
+ return assert(map[arch], "unknown arch(%s)!", arch)
+end
+
+-- get os
+function _conan_get_os(plat)
+ local map = {macosx = "Macos",
+ windows = "Windows",
+ mingw = "Windows",
+ linux = "Linux",
+ cross = "Linux",
+ iphoneos = "iOS",
+ android = "Android"}
+ return assert(map[plat], "unknown os(%s)!", plat)
+end
+
+-- get build type
+function _conan_get_build_type(mode)
+ if mode == "debug" then
+ return "Debug"
+ else
+ return "Release"
+ end
+end
+
+-- generate compiler profile
+function _conan_generate_compiler_profile(profile, configs, opt)
+ local conf
+ local plat = opt.plat
+ local arch = opt.arch
+ if plat == "windows" then
+ -- https://github.com/conan-io/conan/blob/353c63b16c31c90d370305b5cbb5dc175cf8a443/conan/tools/microsoft/visual.py#L13
+ local vsvers = {["2022"] = "193",
+ ["2019"] = "192",
+ ["2017"] = "191",
+ ["2015"] = "190",
+ ["2013"] = "180",
+ ["2012"] = "170"}
+ local vs = assert(config.get("vs"), "vs not found!")
+ profile:print("compiler=msvc")
+ profile:print("compiler.version=" .. assert(vsvers[vs], "unknown msvc version!"))
+ if configs.vs_runtime then
+ profile:print("compiler.runtime=" .. configs.vs_runtime)
+ end
+ elseif plat == "iphoneos" then
+ local target_minver = nil
+ local xcode = toolchain.load("xcode", {plat = plat, arch = arch})
+ if xcode then
+ target_minver = xcode:config("target_minver")
+ end
+ if target_minver and tonumber(target_minver) > 10 and (arch == "armv7" or arch == "armv7s" or arch == "x86") then
+ target_minver = "10" -- iOS 10 is the maximum deployment target for 32-bit targets
+ end
+ if target_minver then
+ profile:print("os.version=" .. target_minver)
+ end
+ local simulator = xcode:config("appledev") == "simulator"
+ profile:print("os.sdk=" .. (simulator and "iphonesimulator" or "iphoneos"))
+ profile:print("compiler=clang")
+ local version
+ local result = find_tool("clang", {version = true})
+ if result and result.version then
+ local v = semver.try_parse(result.version)
+ if v then
+ version = v:major()
+ end
+ end
+ if version then
+ profile:print("compiler.version=" .. version)
+ end
+ elseif plat == "android" then
+ local ndk = toolchain.load("ndk", {plat = plat, arch = arch})
+ local ndk_sdkver = ndk:config("ndk_sdkver")
+ if ndk_sdkver then
+ profile:print("os.api_level=" .. ndk_sdkver)
+ end
+ local ndk_cxxstl = config.get("ndk_cxxstl")
+ if ndk_cxxstl then
+ profile:print("compiler.libcxx=" .. ndk_cxxstl)
+ end
+ local version
+ local program, toolname = ndk:tool("cc")
+ local result = find_tool(toolname, {program = program, version = true})
+ if result and result.version then
+ local v = semver.try_parse(result.version)
+ if v then
+ version = v:major()
+ end
+ end
+ profile:print("compiler=" .. toolname)
+ if version then
+ profile:print("compiler.version=" .. version)
+ end
+ conf = {}
+ conf["tools.android:ndk_path"] = ndk:config("ndk")
+ else
+ local program, toolname = platform.tool("cc", plat, arch)
+ if toolname == "gcc" or toolname == "clang" then
+ local version
+ local result = find_tool(toolname, {program = program, version = true})
+ if result and result.version then
+ local v = semver.try_parse(result.version)
+ if v then
+ version = v:major()
+ end
+ end
+ profile:print("compiler=" .. toolname)
+ profile:print("compiler.cppstd=gnu17")
+ if toolname == "clang" then
+ profile:print("compiler.libcxx=libc++")
+ else
+ profile:print("compiler.libcxx=libstdc++11")
+ end
+ if version then
+ profile:print("compiler.version=" .. version)
+ end
+ end
+ end
+
+ if conf then
+ profile:print("")
+ profile:print("[conf]")
+ for k, v in pairs(conf) do
+ profile:print("%s=%s", k, v)
+ end
+ end
+end
+
+-- generate build profile
+function _conan_generate_build_profile(configs, opt)
+ local profile = io.open("profile_build.txt", "w")
+ profile:print("[settings]")
+ profile:print("arch=%s", _conan_get_arch(os.arch()))
+ profile:print("build_type=%s", _conan_get_build_type(opt.mode))
+ profile:print("os=%s", _conan_get_os(os.host()))
+ _conan_generate_compiler_profile(profile, configs, {plat = os.host(), arch = os.arch()})
+ profile:close()
+end
+
+-- generate host profile
+function _conan_generate_host_profile(configs, opt)
+ local profile = io.open("profile_host.txt", "w")
+ profile:print("[settings]")
+ profile:print("arch=%s", _conan_get_arch(opt.arch))
+ profile:print("build_type=%s", _conan_get_build_type(opt.mode))
+ profile:print("os=%s", _conan_get_os(opt.plat))
+ _conan_generate_compiler_profile(profile, configs, opt)
+ profile:close()
+end
+
+-- install package
+function main(conan, name, opt)
+
+ -- get configs
+ opt = opt or {}
+ local configs = opt.configs or {}
+
+ -- get build directory
+ local buildir = _conan_get_build_directory(name)
+
+ -- clean the build directory
+ os.tryrm(buildir)
+ if not os.isdir(buildir) then
+ os.mkdir(buildir)
+ end
+
+ -- enter build directory
+ local oldir = os.cd(buildir)
+
+ -- install xmake generator
+ _conan_install_xmake_generator(conan)
+
+ -- generate conanfile.txt
+ _conan_generate_conanfile(name, configs, opt)
+
+ -- generate host profile
+ _conan_generate_host_profile(configs, opt)
+
+ -- generate build profile
+ _conan_generate_build_profile(configs, opt)
+
+ -- install package
+ local argv = {"install", ".", "-g", "XmakeGenerator",
+ "--profile:build=profile_build.txt", "--profile:host=profile_host.txt"}
+ if configs.build then
+ if configs.build == "all" then
+ table.insert(argv, "--build")
+ else
+ table.insert(argv, "--build=" .. configs.build)
+ end
+ end
+
+ -- set custom settings
+ for _, setting in ipairs(configs.settings) do
+ table.insert(argv, "-s")
+ table.insert(argv, setting)
+ end
+
+ -- set remote
+ if configs.remote then
+ table.insert(argv, "-r")
+ table.insert(argv, configs.remote)
+ end
+
+ -- do install
+ os.vrunv(conan.program, argv)
+
+ -- leave build directory
+ os.cd(oldir)
+end
diff --git a/xmake/scripts/conan/extensions/generators/xmake_generator.py b/xmake/scripts/conan/extensions/generators/xmake_generator.py
new file mode 100644
index 000000000..a7298615f
--- /dev/null
+++ b/xmake/scripts/conan/extensions/generators/xmake_generator.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from conan import ConanFile
+from conan.tools.files import save, load
+from conan.tools.microsoft import unix_path, VCVars, is_msvc
+from conan.errors import ConanInvalidConfiguration
+from conan.errors import ConanException
+from conans.model.build_info import CppInfo
+
+class XmakeGenerator:
+ def __init__(self, conanfile):
+ self._conanfile = conanfile
+
+ def filename(self):
+ return "conanbuildinfo.xmake.lua"
+
+ def generate(self):
+ print("XmakeGenerator: generating build info ..")
+
+ # extract all dependencies
+ host_req = self._conanfile.dependencies.host
+ test_req = self._conanfile.dependencies.test
+ build_req = self._conanfile.dependencies.build
+
+ full_req = list(host_req.items()) \
+ + list(test_req.items()) \
+ + list(build_req.items())
+
+ for require, dep in full_req:
+ #dep_name = require.ref.name
+
+ # get aggregate dependency's cppinfo
+ dep_cppinfo = dep.cpp_info.copy()
+ dep_cppinfo.set_relative_base_folder(dep.package_folder)
+ dep_aggregate = dep_cppinfo.aggregated_components()
+
+ # format deps
+ deps = XmakeDepsFormatter(dep_aggregate)
+
+ # make template
+ plat = self._conanfile.settings.os
+ arch = self._conanfile.settings.arch
+ mode = self._conanfile.settings.build_type
+ template = (' {plat}_{arch}_{mode} = \n'
+ ' {{\n'
+ ' includedirs = {{{deps.include_paths}}},\n'
+ ' linkdirs = {{{deps.lib_paths}}},\n'
+ ' links = {{{deps.libs}}},\n'
+ ' frameworkdirs = {{{deps.framework_paths}}},\n'
+ ' frameworks = {{{deps.frameworks}}},\n'
+ ' syslinks = {{{deps.system_libs}}},\n'
+ ' defines = {{{deps.defines}}},\n'
+ ' cxxflags = {{{deps.cppflags}}},\n'
+ ' cflags = {{{deps.cflags}}},\n'
+ ' shflags = {{{deps.sharedlinkflags}}},\n'
+ ' ldflags = {{{deps.exelinkflags}}},\n'
+ ' __bindirs = {{{deps.bin_paths}}},\n'
+ ' __resdirs = {{{deps.res_paths}}},\n'
+ ' __srcdirs = {{{deps.src_paths}}}\n'
+ ' }}')
+
+ # make sections
+ sections = []
+ sections.append(template.format(plat = plat, arch = arch, mode = mode, deps = deps))
+
+ # make content
+ content = "{\n" + ",\n".join(sections) + "\n}"
+ print(content)
+
+ # save content to file
+ with open(self.filename(), 'w') as file:
+ file.write(content)
+
+class XmakeDepsFormatter(object):
+ def __prepare_process_escape_character(self, raw_string):
+ if raw_string.find('\"') != -1:
+ raw_string = raw_string.replace("\"","\\\"")
+ return raw_string
+
+ def __filter_char(self, raw_string):
+ return self.__prepare_process_escape_character(raw_string)
+
+ def __init__(self, deps_cpp_info):
+ includedirs = deps_cpp_info._includedirs if deps_cpp_info._includedirs else []
+ libdirs = deps_cpp_info._libdirs if deps_cpp_info._libdirs else []
+ bindirs = deps_cpp_info._bindirs if deps_cpp_info._bindirs else []
+ resdirs = deps_cpp_info._resdirs if deps_cpp_info._resdirs else []
+ srcdirs = deps_cpp_info._srcdirs if deps_cpp_info._srcdirs else []
+ frameworkdirs = deps_cpp_info._frameworkdirs if deps_cpp_info._frameworkdirs else []
+ libs = deps_cpp_info._libs if deps_cpp_info._libs else []
+ frameworks = deps_cpp_info._frameworks if deps_cpp_info._frameworks else []
+ system_libs = deps_cpp_info._system_libs if deps_cpp_info._system_libs else []
+ defines = deps_cpp_info._defines if deps_cpp_info._defines else []
+ cxxflags = deps_cpp_info._cxxflags if deps_cpp_info._cxxflags else []
+ cflags = deps_cpp_info._cflags if deps_cpp_info._cflags else []
+ sharedlinkflags = deps_cpp_info._sharedlinkflags if deps_cpp_info._sharedlinkflags else []
+ exelinkflags = deps_cpp_info._exelinkflags if deps_cpp_info._exelinkflags else []
+
+ self.include_paths = ",\n".join('"%s"' % self.__filter_char(p.replace("\\", "/")) for p in includedirs)
+ self.lib_paths = ",\n".join('"%s"' % self.__filter_char(p.replace("\\", "/")) for p in libdirs)
+ self.bin_paths = ",\n".join('"%s"' % self.__filter_char(p.replace("\\", "/")) for p in bindirs)
+ self.res_paths = ",\n".join('"%s"' % self.__filter_char(p.replace("\\", "/")) for p in resdirs)
+ self.src_paths = ",\n".join('"%s"' % self.__filter_char(p.replace("\\", "/")) for p in srcdirs)
+ self.framework_paths = ",\n".join('"%s"' % self.__filter_char(p.replace("\\", "/")) for p in frameworkdirs)
+ self.libs = ", ".join('"%s"' % p for p in libs)
+ self.frameworks = ", ".join('"%s"' % p for p in frameworks)
+ self.system_libs = ", ".join('"%s"' % p for p in system_libs)
+ self.defines = ", ".join('"%s"' % self.__filter_char(p) for p in defines)
+ self.cppflags = ", ".join('"%s"' % p for p in cxxflags)
+ self.cflags = ", ".join('"%s"' % p for p in cflags)
+ self.sharedlinkflags = ", ".join('"%s"' % p for p in sharedlinkflags)
+ self.exelinkflags = ", ".join('"%s"' % p for p in exelinkflags)
+