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

Improve rust to support cross build deps #4052

Merged
merged 14 commits into from
Aug 9, 2023
10 changes: 10 additions & 0 deletions tests/projects/rust/cargo_deps_cross_build/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "demo"
version = "0.1.0"
edition = "2021"

[dependencies]
spin = "^0.9"

[target.'cfg(target_arch = "aarch64")'.dependencies]
aarch64-cpu = "^9.3"
10 changes: 10 additions & 0 deletions tests/projects/rust/cargo_deps_cross_build/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// src/main.rs
#![no_main]
#![no_std]

use core::panic::PanicInfo;

#[panic_handler]
fn panic(_panic: &PanicInfo<'_>) -> ! {
loop {}
}
14 changes: 14 additions & 0 deletions tests/projects/rust/cargo_deps_cross_build/xmake.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
-- rustup target add aarch64-unknown-none
-- xmake f -a aarch64-unknown-none

set_arch("aarch64-unknown-none")
add_rules("mode.release", "mode.debug")
add_requires("cargo::test", {configs = {
std = false,
main = false,
cargo_toml = path.join(os.projectdir(), "Cargo.toml")}})

target("test")
set_kind("binary")
add_files("src/main.rs")
add_packages("cargo::test")
8 changes: 5 additions & 3 deletions xmake/modules/package/manager/cargo/configurations.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
function main()
return
{
features = {description = "set the features of dependency."},
default_features = {description = "enables or disables any defaults provided by the dependency.", default = true},
cargo_toml = {description = "set Cargo.toml file path"}
features = {description = "Set the features of dependency."},
default_features = {description = "Enable or disable any defaults provided by the dependency.", default = true},
std = {description = "Enable or disable std module."},
main = {description = "Enable or disable main entry function."},
cargo_toml = {description = "Set Cargo.toml file path"}
}
end
58 changes: 39 additions & 19 deletions xmake/modules/package/manager/cargo/find_package.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@
import("core.base.option")
import("core.base.semver")
import("core.base.hashset")
import("core.base.json")
import("core.project.config")
import("core.project.target")
import("lib.detect.find_tool")
import("lib.detect.find_file")
import("private.tools.rust.check_target")

-- get cargo registry directory
function _get_cargo_registrydir()
Expand Down Expand Up @@ -82,30 +84,48 @@ function _get_libname(name)
end

-- get the name set of libraries
function _get_names_of_libraries(name, configs)
function _get_names_of_libraries(name, opt)
local configs = opt.configs or {}
local names = hashset.new()
if configs.cargo_toml then
local dependencies = false
local cargo_file = io.open(configs.cargo_toml)
for line in cargo_file:lines() do
line = line:trim()
if not dependencies and line == "[dependencies]" then
dependencies = true
elseif dependencies then
if not line:startswith("[") then
local splitinfo = line:split("=", {plain = true})
if splitinfo and #splitinfo > 1 then
name = splitinfo[1]:trim()
if #name > 0 then
names:insert(_get_libname(name))
end
end
else
local cargo = assert(find_tool("cargo"), "cargo not found!")
local cargo_args = {"metadata", "--format-version", "1", "--manifest-path", configs.cargo_toml, "--color", "never"}
local target = check_target(opt.arch, true) and opt.arch or nil
if target then
table.insert(cargo_args, "--filter-platform")
table.insert(cargo_args, target)
end
if configs.features then
table.insert(cargo_args, "--features")
table.insert(cargo_args, table.concat(configs.features, ","))
end
if configs.default_features == false then
table.insert(cargo_args, "--no-default-features")
end

local output = os.iorunv(cargo.program, cargo_args)
local metadata = json.decode(output)

-- fetch the direct dependencies list regradless of the target platform
table.insert(cargo_args, "--no-deps")
output = os.iorunv(cargo.program, cargo_args)
local metadata_no_deps = json.decode(output)
-- FIXME: should consider the case of multiple packages in a workspace!
local direct_deps = metadata_no_deps.packages[1].dependencies

-- get the intersection of the direct dependencies and all dependencies for the target platform
for _, dep in ipairs(direct_deps) do
local dep_metadata
for _, pkg in ipairs(metadata.packages) do
if pkg.name == dep.name then
dep_metadata = pkg
break
end
end
if dep_metadata then
names:insert(_get_libname(dep.name))
end
end
cargo_file:close()
else
names:insert(_get_libname(name))
end
Expand All @@ -124,7 +144,7 @@ function main(name, opt)
local configs = opt.configs or {}

-- get names of libraries
local names = _get_names_of_libraries(name, configs)
local names = _get_names_of_libraries(name, opt)
assert(not names:empty())

local frameworkdirs
Expand Down
48 changes: 42 additions & 6 deletions xmake/modules/package/manager/cargo/install_package.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import("core.base.option")
import("core.project.config")
import("lib.detect.find_tool")
import("private.tools.rust.check_target")

-- install package
--
Expand Down Expand Up @@ -52,6 +53,11 @@ function main(name, opt)
require_version = "*"
end

-- get target
-- e.g. x86_64-pc-windows-msvc, aarch64-unknown-none
-- @see https://github.com/xmake-io/xmake/issues/4049
local target = check_target(opt.arch, true) and opt.arch or nil

-- generate Cargo.toml
local sourcedir = path.join(opt.cachedir, "source")
local cargotoml = path.join(sourcedir, "Cargo.toml")
Expand Down Expand Up @@ -86,12 +92,38 @@ function main(name, opt)
tomlfile:close()
end

-- generate .cargo/config.toml
local configtoml = path.join(sourcedir, ".cargo", "config.toml")
if target then
io.writefile(configtoml, format([[
[build]
target = "%s"
]], target))
end

-- generate main.rs
io.writefile(path.join(sourcedir, "src", "main.rs"), [[
fn main() {
println!("Hello, world!");
}
]])
local file = io.open(path.join(sourcedir, "src", "main.rs"), "w")
if configs.main == false then
file:print("#![no_main]")
end
if configs.std == false then
file:print("#![no_std]")
end
if configs.main == false then
file:print([[
use core::panic::PanicInfo;

#[panic_handler]
fn panic(_panic: &PanicInfo<'_>) -> ! {
loop {}
}]])
else
file:print([[
fn main() {
println!("Hello, world!");
}]])
end
file:close()

-- do build
local argv = {"build"}
Expand All @@ -106,5 +138,9 @@ fn main() {
-- do install
local installdir = opt.installdir
os.tryrm(path.join(installdir, "lib"))
os.vcp(path.join(sourcedir, "target", opt.mode == "debug" and "debug" or "release", "deps"), path.join(installdir, "lib"))
if target then
os.vcp(path.join(sourcedir, "target", target, opt.mode == "debug" and "debug" or "release", "deps"), path.join(installdir, "lib"))
else
os.vcp(path.join(sourcedir, "target", opt.mode == "debug" and "debug" or "release", "deps"), path.join(installdir, "lib"))
end
end
76 changes: 76 additions & 0 deletions xmake/modules/private/tools/rust/check_target.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
--!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 w568w
-- @file check_target.lua
--

-- imports
import("lib.detect.find_tool")

-- get rustc supported targets
--
-- @return the supported target list. If rustc not found, return nil
function _get_rustc_supported_target()
local rustc = find_tool("rustc")
if not rustc then
return nil
end
local output = os.iorunv(rustc.program, {"--print", "target-list"})
return output:split('\n')
end

-- check whether the target is supported by rustc
--
-- @param arch the target name, e.g. x86_64-unknown-linux-gnu
-- @param precise whether to check the target precisely (i.e. check by rustc), otherwise only by syntax
--
-- @return true if arch != nil and the target is supported by rustc, otherwise false
function main(arch, precise)

if not arch then
return false
end

-- 1: check by syntax
local result = false
local archs = arch:split("%-")
if #archs >= 2 then
result = true
else
wprint("the arch \"%s\" is NOT a valid target triple, will be IGNORED and may cause compilation errors, please check it again", arch)
end

-- 2: check by rustc
if not precise then
return result
end
result = false
local rustc_supported_target = _get_rustc_supported_target()
if rustc_supported_target then
for _, v in ipairs(rustc_supported_target) do
if v == arch then
result = true
break
end
end
if not result then
wprint("the arch \"%s\" is NOT supported by rustc, will be IGNORED and may cause compilation errors, please check it again", arch)
end
end

return result
end
15 changes: 9 additions & 6 deletions xmake/toolchains/rust/xmake.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,24 @@
-- @file xmake.lua
--

-- define toolchain
toolchain("rust")

-- set homepage
set_homepage("https://www.rust-lang.org/")
set_description("Rust Programming Language Compiler")

-- set toolset
set_toolset("rc", "$(env RC)", "rustc")
set_toolset("rcld", "$(env RC)", "rustc")
set_toolset("rcsh", "$(env RC)", "rustc")
set_toolset("rcar", "$(env RC)", "rustc")

-- on load
on_load(function (toolchain)
toolchain:set("rcshflags", "")
toolchain:set("rcldflags", "")
-- e.g. x86_64-pc-windows-msvc, aarch64-unknown-none
local arch = toolchain:arch()
if arch and #arch:split("%-") > 1 then
toolchain:add("rcshflags", "--target=" .. arch)
toolchain:add("rcldflags", "--target=" .. arch)
else
toolchain:set("rcshflags", "")
toolchain:set("rcldflags", "")
end
end)
3 changes: 2 additions & 1 deletion xmake/toolchains/xcode/load_macosx.lua
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ function main(toolchain)
-- init flags for c/c++
toolchain:add("ldflags", "-stdlib=libc++")
toolchain:add("shflags", "-stdlib=libc++")
toolchain:add("syslinks", "z")
toolchain:add("ldflags", "-lz")
toolchain:add("shflags", "-lz")

-- init flags for objc/c++ (with ldflags and shflags)
-- we can use `add_mxflags("-fno-objc-arc")` to override it in xmake.lua
Expand Down