diff options
| author | ruki <[email protected]> | 2021-11-12 22:42:04 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-11-12 22:42:04 +0800 |
| commit | d242a83f354f6643b4355dd3c082fad3dd037e06 (patch) | |
| tree | 4825f41edef33ed03e7f9174000538ff43c2a51b | |
| parent | 65f1179b9df1886c23dce6bbe4dfdb25ae912b9b (diff) | |
| parent | 1130f7b98a942da147a92040dd640ce84b561128 (diff) | |
Merge pull request #1823 from xmake-io/rustc
Improve rust project to support mixed complation
25 files changed, 334 insertions, 48 deletions
diff --git a/tests/projects/rust/cxx_call_rust_library/src/bridge.rsx b/tests/projects/rust/cxx_call_rust_library/src/bridge.rsx new file mode 100644 index 000000000..3710f4bfd --- /dev/null +++ b/tests/projects/rust/cxx_call_rust_library/src/bridge.rsx @@ -0,0 +1,6 @@ +#[cxx::bridge] +mod foo { + extern "Rust" { + fn add(a: i32, b: i32) -> i32; + } +} diff --git a/tests/projects/rust/cxx_call_rust_library/src/foo.rs b/tests/projects/rust/cxx_call_rust_library/src/foo.rs new file mode 100644 index 000000000..0c4975fa2 --- /dev/null +++ b/tests/projects/rust/cxx_call_rust_library/src/foo.rs @@ -0,0 +1,13 @@ +#[cxx::bridge] +mod foo { + extern "Rust" { + fn add(a: i32, b: i32) -> i32; + } +} + +pub fn add(a: i32, b: i32) -> i32 +{ + return a + b; +} + + diff --git a/tests/projects/rust/cxx_call_rust_library/src/main.cc b/tests/projects/rust/cxx_call_rust_library/src/main.cc new file mode 100644 index 000000000..c0d600fd3 --- /dev/null +++ b/tests/projects/rust/cxx_call_rust_library/src/main.cc @@ -0,0 +1,8 @@ +#include <stdio.h> +#include "bridge.rs.h" + +int main(int argc, char** argv) +{ + printf("add(1, 2) == %d\n", add(1, 2)); + return 0; +} diff --git a/tests/projects/rust/cxx_call_rust_library/xmake.lua b/tests/projects/rust/cxx_call_rust_library/xmake.lua new file mode 100644 index 000000000..fb3a48171 --- /dev/null +++ b/tests/projects/rust/cxx_call_rust_library/xmake.lua @@ -0,0 +1,13 @@ +add_rules("mode.debug", "mode.release") + +target("foo") + set_kind("static") + add_files("src/foo.rs") + set_values("rust.cratetype", "staticlib") + +target("test") + set_kind("binary") + add_rules("rust.cxxbridge") + add_deps("foo") + add_files("src/main.cc") + add_files("src/bridge.rsx") diff --git a/tests/projects/rust/rust_call_cxx_library/src/foo.cc b/tests/projects/rust/rust_call_cxx_library/src/foo.cc new file mode 100644 index 000000000..9d989119e --- /dev/null +++ b/tests/projects/rust/rust_call_cxx_library/src/foo.cc @@ -0,0 +1,4 @@ +extern "C" int add(int a, int b) +{ + return a + b; +} diff --git a/tests/projects/rust/rust_call_cxx_library/src/main.rs b/tests/projects/rust/rust_call_cxx_library/src/main.rs new file mode 100644 index 000000000..1eac379d2 --- /dev/null +++ b/tests/projects/rust/rust_call_cxx_library/src/main.rs @@ -0,0 +1,9 @@ +extern "C" { + fn add(a: i32, b: i32) -> i32; +} + +fn main() { + unsafe { + println!("add(1, 2) = {}", add(1, 2)); + } +} diff --git a/tests/projects/rust/rust_call_cxx_library/test.lua b/tests/projects/rust/rust_call_cxx_library/test.lua new file mode 100644 index 000000000..92168a8c1 --- /dev/null +++ b/tests/projects/rust/rust_call_cxx_library/test.lua @@ -0,0 +1,10 @@ +-- main entry +function main(t) + + -- build project + if is_host("macosx") and os.arch() ~= "arm64" then + t:build() + else + return t:skip("wrong host platform") + end +end diff --git a/tests/projects/rust/rust_call_cxx_library/xmake.lua b/tests/projects/rust/rust_call_cxx_library/xmake.lua new file mode 100644 index 000000000..e150aca4a --- /dev/null +++ b/tests/projects/rust/rust_call_cxx_library/xmake.lua @@ -0,0 +1,12 @@ +add_rules("mode.debug", "mode.release") + +target("foo") + set_kind("static") + add_files("src/foo.cc") + +target("test") + set_kind("binary") + add_deps("foo") + add_files("src/main.rs") + + diff --git a/tests/projects/rust/static_library/src/interfaces.rs b/tests/projects/rust/shared_library/src/foo.rs index 277008ba4..277008ba4 100644 --- a/tests/projects/rust/static_library/src/interfaces.rs +++ b/tests/projects/rust/shared_library/src/foo.rs diff --git a/tests/projects/rust/shared_library/src/main.rs b/tests/projects/rust/shared_library/src/main.rs new file mode 100644 index 000000000..24f23d84b --- /dev/null +++ b/tests/projects/rust/shared_library/src/main.rs @@ -0,0 +1,7 @@ +extern crate foo; + +fn main() +{ + println!("hello xmake!"); + println!("add: {}", foo::add(1, 1)); +} diff --git a/tests/projects/rust/shared_library/xmake.lua b/tests/projects/rust/shared_library/xmake.lua new file mode 100644 index 000000000..edacfe4d6 --- /dev/null +++ b/tests/projects/rust/shared_library/xmake.lua @@ -0,0 +1,12 @@ +add_rules("mode.debug", "mode.release") + +target("foo") + set_kind("shared") + add_files("src/foo.rs") + +target("test") + set_kind("binary") + add_deps("foo") + add_files("src/main.rs") + + diff --git a/xmake/templates/rust/static/project/src/interfaces.rs b/tests/projects/rust/static_library/src/foo.rs index 277008ba4..277008ba4 100644 --- a/xmake/templates/rust/static/project/src/interfaces.rs +++ b/tests/projects/rust/static_library/src/foo.rs diff --git a/tests/projects/rust/static_library/src/main.rs b/tests/projects/rust/static_library/src/main.rs index 0cd4449d1..24f23d84b 100644 --- a/tests/projects/rust/static_library/src/main.rs +++ b/tests/projects/rust/static_library/src/main.rs @@ -1,7 +1,7 @@ -extern crate interfaces; +extern crate foo; -fn main() +fn main() { println!("hello xmake!"); - println!("add: {}", interfaces::add(1, 1)); + println!("add: {}", foo::add(1, 1)); } diff --git a/tests/projects/rust/static_library/xmake.lua b/tests/projects/rust/static_library/xmake.lua index fa38d17e5..c50e50874 100644 --- a/tests/projects/rust/static_library/xmake.lua +++ b/tests/projects/rust/static_library/xmake.lua @@ -1,12 +1,12 @@ add_rules("mode.debug", "mode.release") -target("interfaces") +target("foo") set_kind("static") - add_files("src/interfaces.rs") + add_files("src/foo.rs") target("test") set_kind("binary") - add_deps("interfaces") + add_deps("foo") add_files("src/main.rs") diff --git a/xmake/core/project/target.lua b/xmake/core/project/target.lua index 08ab720c0..c48d64c47 100644 --- a/xmake/core/project/target.lua +++ b/xmake/core/project/target.lua @@ -1609,8 +1609,8 @@ function _instance:sourcekinds() local sourcekinds = self._SOURCEKINDS if not sourcekinds then sourcekinds = {} - for _, sourcefile in pairs(self:sourcefiles()) do - local sourcekind = self:sourcekind_of(sourcefile) + for _, sourcebatch in pairs(self:sourcebatches()) do + local sourcekind = sourcebatch.sourcekind if sourcekind then table.insert(sourcekinds, sourcekind) end diff --git a/xmake/languages/rust/xmake.lua b/xmake/languages/rust/xmake.lua index dc6ae3d15..b07617a61 100644 --- a/xmake/languages/rust/xmake.lua +++ b/xmake/languages/rust/xmake.lua @@ -25,7 +25,7 @@ language("rust") set_targetkinds {binary = "rcld", static = "rcar", shared = "rcsh"} set_targetflags {binary = "ldflags", static = "arflags", shared = "shflags"} set_langkinds {rust = "rc"} - set_mixingkinds("rc") + set_mixingkinds("rc", "cc", "cxx") on_load("load") on_check_main("check_main") @@ -45,13 +45,27 @@ language("rust") , "target.symbols" , "toolchain.linkdirs" , "toolchain.rpathdirs" + , "config.links" + , "target.links" + , "toolchain.links" + , "config.syslinks" + , "target.syslinks" + , "toolchain.syslinks" } , shared = { "config.linkdirs" , "target.linkdirs" + , "target.rpathdirs" , "target.strip" , "target.symbols" , "toolchain.linkdirs" + , "toolchain.rpathdirs" + , "config.links" + , "target.links" + , "toolchain.links" + , "config.syslinks" + , "target.syslinks" + , "toolchain.syslinks" } , static = { "target.strip" diff --git a/xmake/modules/core/tools/rustc.lua b/xmake/modules/core/tools/rustc.lua index a30a389af..fa358e897 100644 --- a/xmake/modules/core/tools/rustc.lua +++ b/xmake/modules/core/tools/rustc.lua @@ -25,18 +25,6 @@ import("core.project.project") -- init it function init(self) - - -- init arflags - self:set("rcarflags", "--crate-type=lib") - - -- init shflags - self:set("rcshflags", "--crate-type=dylib") - - -- init ldflags - self:set("rcldflags", "--crate-type=bin") - - -- init the file formats - self:set("formats", { static = "lib$(name).rlib" }) end -- make the optimize flag @@ -67,9 +55,47 @@ function nf_linkdir(self, dir) return {"-L" .. dir} end +-- make the link flag +function nf_link(self, lib) + return "-l" .. lib +end + +-- make the syslink flag +function nf_syslink(self, lib) + return nf_link(self, lib) +end + +-- make the rpathdir flag +function nf_rpathdir(self, dir) + dir = path.translate(dir) + if self:has_flags({"-C", "link-arg=-Wl,-rpath=$ORIGIN"}, "ldflags") then + return {"-C", "link-arg=-Wl,-rpath=" .. (dir:gsub("@[%w_]+", function (name) + local maps = {["@loader_path"] = "$ORIGIN", ["@executable_path"] = "$ORIGIN"} + return maps[name] + end))} + elseif self:has_flags({"-C", "link-arg=-Xlinker", "-C", "link-arg=-rpath", "-C", "link-arg=-Xlinker", "-C", "link-arg=@loader_path"}, "ldflags") then + return {"-C", "link-arg=-Xlinker", + "-C", "link-arg=-rpath", + "-C", "link-arg=-Xlinker", + "-C", "link-arg=" .. (dir:gsub("%$ORIGIN", "@loader_path"))} + end +end + -- make the build arguments list function buildargv(self, sourcefiles, targetkind, targetfile, flags) - return self:program(), table.join(flags, "-o", targetfile, sourcefiles) + -- add rpath for dylib (macho), e.g. -install_name @rpath/file.dylib + local flags_extra = {} + if targetkind == "shared" and is_plat("macosx", "iphoneos", "watchos") then + table.insert(flags_extra, "-C") + table.insert(flags_extra, "link-arg=-Xlinker") + table.insert(flags_extra, "-C") + table.insert(flags_extra, "link-arg=-install_name") + table.insert(flags_extra, "-C") + table.insert(flags_extra, "link-arg=-Xlinker") + table.insert(flags_extra, "-C") + table.insert(flags_extra, "link-arg=@rpath/" .. path.filename(targetfile)) + end + return self:program(), table.join(flags, flags_extra, "-o", targetfile, sourcefiles) end -- build the target file diff --git a/xmake/modules/detect/tools/find_cxxbridge.lua b/xmake/modules/detect/tools/find_cxxbridge.lua new file mode 100644 index 000000000..400573fa7 --- /dev/null +++ b/xmake/modules/detect/tools/find_cxxbridge.lua @@ -0,0 +1,52 @@ +--!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 find_cxxbridge.lua +-- + +-- imports +import("lib.detect.find_program") +import("lib.detect.find_programver") + +-- find nim +-- +-- @param opt the argument options, e.g. {version = true} +-- +-- @return program, version +-- +-- @code +-- +-- local nim = find_cxxbridge() +-- local nim, version = find_cxxbridge({program = "cxxbridge", version = true}) +-- +-- @endcode +-- +function main(opt) + + -- init options + opt = opt or {} + + -- find program + local program = find_program(opt.program or "cxxbridge", opt) + + -- find program version + local version = nil + if program and opt.version then + version = find_programver(program, opt) + end + return program, version +end diff --git a/xmake/modules/detect/tools/rustc/has_flags.lua b/xmake/modules/detect/tools/rustc/has_flags.lua index 904a3c85a..e1696e454 100644 --- a/xmake/modules/detect/tools/rustc/has_flags.lua +++ b/xmake/modules/detect/tools/rustc/has_flags.lua @@ -21,6 +21,16 @@ -- imports import("core.cache.detectcache") +-- is linker? +function _islinker(flags, opt) + local flags_str = table.concat(flags, " ") + if flags_str:startswith("-C linkarg=") then + return true + end + local toolkind = opt.toolkind or "" + return toolkind == "ld" or toolkind == "sh" or toolkind:endswith("ld") or toolkind:endswith("sh") +end + -- try running function _try_running(...) @@ -64,7 +74,7 @@ function _check_from_arglist(flags, opt) end -- try running to check flags -function _check_try_running(flags, opt) +function _check_try_running(flags, opt, islinker) -- make an stub source file local sourcefile = path.join(os.tmpdir(), "detect", "rustc_has_flags.rs") @@ -72,14 +82,15 @@ function _check_try_running(flags, opt) io.writefile(sourcefile, "fn main() {\n}") end - -- check it + -- check flags for linker + if islinker then + return _try_running(opt.program, table.join("--crate-type=bin", flags, "-o", os.tmpfile(), sourcefile), opt) + end + + -- check flags for compiler local objectfile = os.tmpfile() .. ".o" local ok, errors = _try_running(opt.program, table.join("--emit", "obj", flags, "-o", objectfile, sourcefile)) - - -- remove files os.tryrm(objectfile) - - -- ok? return ok, errors end @@ -91,12 +102,15 @@ end -- function main(flags, opt) + -- is linker? + local islinker = _islinker(flags, opt) + -- attempt to check it from the argument list if _check_from_arglist(flags, opt) then return true end -- try running to check it - return _check_try_running(flags, opt) + return _check_try_running(flags, opt, islinker) end diff --git a/xmake/rules/rust/build/cxxbridge.lua b/xmake/rules/rust/build/cxxbridge.lua new file mode 100644 index 000000000..84b1f7fea --- /dev/null +++ b/xmake/rules/rust/build/cxxbridge.lua @@ -0,0 +1,50 @@ +--!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 cxxbridge.lua +-- + +-- imports +import("core.base.option") +import("lib.detect.find_tool") + +function main(target, batchcmds, sourcefile, opt) + local cxxbridge = assert(find_tool("cxxbridge"), "cxxbridge not found!") + + -- get c/c++ source file for cxxbridge + local headerfile = path.join(target:autogendir(), "rules", "cxxbridge", path.basename(sourcefile) .. ".rs.h") + local sourcefile_cx = path.join(target:autogendir(), "rules", "cxxbridge", path.basename(sourcefile) .. ".rs.cc") + + -- add includedirs + target:add("includedirs", path.directory(headerfile)) + + -- add objectfile + local objectfile = target:objectfile(sourcefile_cx) + table.insert(target:objectfiles(), objectfile) + + -- add commands + batchcmds:show_progress(opt.progress, "${color.build.object}compiling.cxxbridge %s", sourcefile) + batchcmds:mkdir(path.directory(sourcefile_cx)) + batchcmds:vrunv(cxxbridge.program, {sourcefile}, {stdout = sourcefile_cx}) + batchcmds:vrunv(cxxbridge.program, {sourcefile, "--header"}, {stdout = headerfile}) + batchcmds:compile(sourcefile_cx, objectfile) + + -- add deps + batchcmds:add_depfiles(sourcefile) + batchcmds:set_depmtime(os.mtime(objectfile)) + batchcmds:set_depcache(target:dependfile(objectfile)) +end diff --git a/xmake/rules/rust/xmake.lua b/xmake/rules/rust/xmake.lua index a8ccae429..e0952b72e 100644 --- a/xmake/rules/rust/xmake.lua +++ b/xmake/rules/rust/xmake.lua @@ -18,16 +18,46 @@ -- @file xmake.lua -- --- define rule: rust.build +-- generate bridge.rs.cc/h to call rust library in c++ code +-- @see https://cxx.rs/build/other.html +rule("rust.cxxbridge") + set_extensions(".rsx") + on_load(function (target) + if not target:get("languages") then + target:set("languages", "c++11") + end + end) + before_buildcmd_file("build.cxxbridge") + rule("rust.build") set_sourcekinds("rc") + on_load(function (target) + local cratetype = target:values("rust.cratetype") + if cratetype == "staticlib" then + assert(target:is_static(), "target(%s) must be static kind for cratetype(staticlib)!", target:name()) + target:add("arflags", "--crate-type=staticlib") + elseif cratetype == "cdylib" then + assert(target:is_shared(), "target(%s) must be shared kind for cratetype(cdylib)!", target:name()) + target:add("shflags", "--crate-type=cdylib") + target:add("shflags", "-C prefer-dynamic") + elseif target:is_static() then + target:set("extension", ".rlib") + target:add("arflags", "--crate-type=lib") + target:data_set("inherit.links.deplink", false) + elseif target:is_shared() then + target:add("shflags", "--crate-type=dylib") + -- fix cannot satisfy dependencies so `std` only shows up once + -- https://github.com/rust-lang/rust/issues/19680 + -- + -- but it will link dynamic @rpath/libstd-xxx.dylib, + -- so we can no longer modify and set other rpath paths + target:add("shflags", "-C prefer-dynamic") + elseif target:is_binary() then + target:add("ldflags", "--crate-type=bin") + end + end) on_build("build.target") --- define rule: rust rule("rust") - - -- add build rules add_deps("rust.build") - - -- inherit links and linkdirs of all dependent targets by default add_deps("utils.inherit.links") diff --git a/xmake/rules/utils/inherit_links/inherit_links.lua b/xmake/rules/utils/inherit_links/inherit_links.lua index d5567b605..805f535d8 100644 --- a/xmake/rules/utils/inherit_links/inherit_links.lua +++ b/xmake/rules/utils/inherit_links/inherit_links.lua @@ -46,7 +46,6 @@ function _add_export_value(target, name, value) end end --- main entry function main(target) -- disable inherit.links for `add_deps()`? @@ -59,12 +58,15 @@ function main(target) if targetkind == "shared" or targetkind == "static" then local targetfile = target:targetfile() - -- we need move target link to head - _add_export_value(target, "links", target:linkname()) - local links = target:get("links", {rawref = true}) - if links and type(links) == "table" and #links > 1 then - table.insert(links, 1, links[#links]) - table.remove(links, #links) + -- rust maybe will disable inherit links, only inherit linkdirs + if target:data("inherit.links.deplink") ~= false then + -- we need move target link to head + _add_export_value(target, "links", target:linkname()) + local links = target:get("links", {rawref = true}) + if links and type(links) == "table" and #links > 1 then + table.insert(links, 1, links[#links]) + table.remove(links, #links) + end end _add_export_value(target, "linkdirs", path.directory(targetfile)) diff --git a/xmake/templates/rust/static/project/src/foo.rs b/xmake/templates/rust/static/project/src/foo.rs new file mode 100644 index 000000000..277008ba4 --- /dev/null +++ b/xmake/templates/rust/static/project/src/foo.rs @@ -0,0 +1,5 @@ +pub fn add(a: i32, b: i32) -> i32 +{ + return a + b; +} + diff --git a/xmake/templates/rust/static/project/src/main.rs b/xmake/templates/rust/static/project/src/main.rs index 24049d150..24f23d84b 100644 --- a/xmake/templates/rust/static/project/src/main.rs +++ b/xmake/templates/rust/static/project/src/main.rs @@ -1,7 +1,7 @@ -extern crate interfaces; +extern crate foo; fn main() { println!("hello xmake!"); - println!("add: {}", interfaces::add(1, 1)); + println!("add: {}", foo::add(1, 1)); } diff --git a/xmake/templates/rust/static/project/xmake.lua b/xmake/templates/rust/static/project/xmake.lua index a4761d2dc..79a9ac569 100644 --- a/xmake/templates/rust/static/project/xmake.lua +++ b/xmake/templates/rust/static/project/xmake.lua @@ -1,11 +1,10 @@ -target("interfaces") +target("foo") set_kind("static") - add_files("src/interfaces.rs") + add_files("src/foo.rs") target("${TARGETNAME}_demo") set_kind("binary") - add_deps("interfaces") + add_deps("foo") add_files("src/main.rs") - add_linkdirs("$(buildir)") ${FAQ} |
