diff options
| author | Arthur LAURENT <[email protected]> | 2025-10-23 23:40:11 +0200 |
|---|---|---|
| committer | Arthur LAURENT <[email protected]> | 2025-10-23 23:40:11 +0200 |
| commit | c1b73a9a9dc3eba4dc96efc9cab7314b5eca9b9b (patch) | |
| tree | 4421086bfb6caeb01376de837185a1a4658da600 | |
| parent | 3a9b7a4db2c851415be0282a36e60deecd7f53f1 (diff) | |
feat(swift) implement swift => c++/obj interop
| -rw-r--r-- | tests/projects/swift/cxx_interop/lib/fibonacci/fibonacci.swift | 7 | ||||
| -rw-r--r-- | tests/projects/swift/cxx_interop/src/fibonacci.cpp | 7 | ||||
| -rw-r--r-- | tests/projects/swift/cxx_interop/xmake.lua | 8 | ||||
| -rw-r--r-- | tests/projects/swift/cxx_interop_lib/lib/fibonacci/fibonacci.swift | 7 | ||||
| -rw-r--r-- | tests/projects/swift/cxx_interop_lib/src/fibonacci.cpp | 7 | ||||
| -rw-r--r-- | tests/projects/swift/cxx_interop_lib/xmake.lua | 12 | ||||
| -rw-r--r-- | xmake/core/tool/compiler.lua | 7 | ||||
| -rw-r--r-- | xmake/rules/swift/xmake.lua | 165 | ||||
| -rw-r--r-- | xmake/toolchains/xcode/load_watchos.lua | 1 |
9 files changed, 220 insertions, 1 deletions
diff --git a/tests/projects/swift/cxx_interop/lib/fibonacci/fibonacci.swift b/tests/projects/swift/cxx_interop/lib/fibonacci/fibonacci.swift new file mode 100644 index 000000000..24149f613 --- /dev/null +++ b/tests/projects/swift/cxx_interop/lib/fibonacci/fibonacci.swift @@ -0,0 +1,7 @@ +public func fibonacciSwift(_ x: CInt) -> CInt { + print("x [swift]: \(x)") + if x <= 1 { + return 1 + } + return fibonacciSwift(x - 1) + fibonacciSwift(x - 2) +} diff --git a/tests/projects/swift/cxx_interop/src/fibonacci.cpp b/tests/projects/swift/cxx_interop/src/fibonacci.cpp new file mode 100644 index 000000000..af50b1171 --- /dev/null +++ b/tests/projects/swift/cxx_interop/src/fibonacci.cpp @@ -0,0 +1,7 @@ +#include <fibonacci-Swift.h> +#include <iostream> + +int main(int argc, char ** argv) { + std::cout << SwiftFibonacci::fibonacciSwift(5) << std::endl; + return 0; +} diff --git a/tests/projects/swift/cxx_interop/xmake.lua b/tests/projects/swift/cxx_interop/xmake.lua new file mode 100644 index 000000000..cd5ef0469 --- /dev/null +++ b/tests/projects/swift/cxx_interop/xmake.lua @@ -0,0 +1,8 @@ +target("cxx_interop") + set_kind("binary") + set_languages("cxx20") + add_files("lib/**.swift", {public = true}) + add_files("src/**.cpp") + set_values("swift.modulename", "SwiftFibonacci") + set_values("swift.interop", "cxx") + set_values("swift.interop.headername", "fibonacci-Swift.h") diff --git a/tests/projects/swift/cxx_interop_lib/lib/fibonacci/fibonacci.swift b/tests/projects/swift/cxx_interop_lib/lib/fibonacci/fibonacci.swift new file mode 100644 index 000000000..24149f613 --- /dev/null +++ b/tests/projects/swift/cxx_interop_lib/lib/fibonacci/fibonacci.swift @@ -0,0 +1,7 @@ +public func fibonacciSwift(_ x: CInt) -> CInt { + print("x [swift]: \(x)") + if x <= 1 { + return 1 + } + return fibonacciSwift(x - 1) + fibonacciSwift(x - 2) +} diff --git a/tests/projects/swift/cxx_interop_lib/src/fibonacci.cpp b/tests/projects/swift/cxx_interop_lib/src/fibonacci.cpp new file mode 100644 index 000000000..af50b1171 --- /dev/null +++ b/tests/projects/swift/cxx_interop_lib/src/fibonacci.cpp @@ -0,0 +1,7 @@ +#include <fibonacci-Swift.h> +#include <iostream> + +int main(int argc, char ** argv) { + std::cout << SwiftFibonacci::fibonacciSwift(5) << std::endl; + return 0; +} diff --git a/tests/projects/swift/cxx_interop_lib/xmake.lua b/tests/projects/swift/cxx_interop_lib/xmake.lua new file mode 100644 index 000000000..f1de85d13 --- /dev/null +++ b/tests/projects/swift/cxx_interop_lib/xmake.lua @@ -0,0 +1,12 @@ +target("fibonacci") + set_kind("$(kind)") + set_languages("cxx20") + add_files("lib/**.swift", {public = true}) + set_values("swift.modulename", "SwiftFibonacci") + set_values("swift.interop", "cxx") + +target("cxx_interop_lib") + set_kind("binary") + set_languages("cxx20") + add_files("src/**.cpp") + add_deps("fibonacci") diff --git a/xmake/core/tool/compiler.lua b/xmake/core/tool/compiler.lua index ff8ce6a5d..5c974edb3 100644 --- a/xmake/core/tool/compiler.lua +++ b/xmake/core/tool/compiler.lua @@ -363,5 +363,12 @@ function compiler:compflags(opt) return self:_preprocess_flags(flags) end +-- get the tool language flags +-- +-- @return flags list +function compiler:languageflags(lang) + return self:_tool():nf_language(lang) +end + -- return module return compiler diff --git a/xmake/rules/swift/xmake.lua b/xmake/rules/swift/xmake.lua index 42611b79c..9e3167292 100644 --- a/xmake/rules/swift/xmake.lua +++ b/xmake/rules/swift/xmake.lua @@ -18,6 +18,165 @@ -- @file xmake.lua -- +rule("swift.interop", function() + set_sourcekinds("sc") + add_orders("swift.interop", "swift.build") + add_orders("swift.interop", "c++") + on_config(function(target) + + import("core.base.json") + + if not target:values("swift.interop") then + return + end + + local sourcebatches = target:sourcebatches() + local sourcebatch = sourcebatches and sourcebatches["swift.build"] + local sourcefiles = sourcebatch and sourcebatch.sourcefiles + local enabled = false + for _, sourcefile in ipairs(sourcefiles) do + local fileconfig = target:fileconfig(sourcefile) + if fileconfig and fileconfig.public then + enabled = true + break + end + end + if not enabled then + return + end + + local sc = target:tool("sc") + assert(sc, "No swift compiler found!") + local outdata, errdata = os.iorunv(sc, {"-print-target-info"}) + assert(outdata, errdata) + + local target_info = json.decode(outdata) + assert(target_info and target_info.paths and target_info.paths.runtimeResourcePath, "Failed to get swift resource path") + target:add("includedirs", target_info.runtimeResourcePath, {public = true}) + + local outdir = target:autogendir("swift") + target:add("includedirs", outdir, {public = true}) + + local mode = (type(target:values("swift.interop")) == "string") and target:values("swift.interop") or "objc" + if mode == "cxx" then + target:add("scflags", "-cxx-interoperability-mode=default") + end + + local headername = (target:values("swift.interop.headername") or (target:name() .. "-Swift")) .. ".h" + local header = path.join(outdir, headername) + target:add("headerfiles", header) + + target:data_set("swift.interop", mode) + target:data_set("swift.interop.outdir", outdir) + end) + + on_prepare(function(target, jobgraph, opt) + + if not target:data("swift.interop") then + return + end + + import("utils.progress") + import("core.base.option") + import("core.language.language") + import("core.project.depend") + + local function _get_target_cppversion() + local compinst = target:compiler("cxx") + local languages = target:get("languages") + for _, language in ipairs(languages) do + if language:startswith("c++") + or language:startswith("cxx") + or language:startswith("gnu++") + or language:startswith("gnuxx") then + local v = compinst:languageflags(language) + if v then return v end + end + end + end + + local mode = target:data("swift.interop") + local sc = target:tool("sc") + assert(sc, "No swift compiler found!") + local outdir = target:data("swift.interop.outdir") + if not os.isdir(outdir) then os.mkdir(outdir) end + assert(outdir) + + local sourcebatches = target:sourcebatches() + local sourcebatch = sourcebatches and sourcebatches["swift.build"] + local sourcefiles = sourcebatch and sourcebatch.sourcefiles + local public_sourcefiles + for _, sourcefile in ipairs(sourcefiles) do + local fileconfig = target:fileconfig(sourcefile) + if fileconfig and fileconfig.public then + public_sourcefiles = public_sourcefiles or {} + table.insert(public_sourcefiles, sourcefile) + end + end + + if public_sourcefiles then + local modulename = target:values("swift.modulename") or target:name() + local headername = (target:values("swift.interop.headername") or (target:name() .. "-Swift")) .. ".h" + local header = path.join(outdir, headername) + + depend.on_changed(function() + jobgraph:add(target:fullname() .. "/gen_swift_header", function(index, total, opt) + local stdflag + if mode == "cxx" then + local cxxstandard = _get_target_cppversion() + if cxxstandard then + stdflag = {"-Xcc", cxxstandard} + end + end + + if opt.progress then + progress.show( + opt.progress, + "${clear}${color.build.target}<%s> generating.swift.header %s", + target:fullname(), + headername + ) + end + + local compinst = import("core.tool.compiler").load("sc") + local _scflags = compinst:compflags({target = target, sourcekind = "sc"}) + local scflags + if target:has_tool("sc", "swift_frontend") then + for _, scflag in ipairs(_scflags) do + scflags = scflags or {} + if not os.isfile(scflag) then + table.insert(scflags, scflag) + end + end + else + scflags = _scflags + end + + + local emit_flag = mode == "cxx" and "-emit-clang-header-path" or "-emit-objc-header-path" + + local flags = table.join({ + "-frontend", + "-typecheck", + emit_flag, + header, + }, + scflags or {}, + stdflag or {}, + public_sourcefiles) + if option.get("verbose") then print(os.args(table.join(sc, flags))) end + + local outdata, errdata = os.iorunv(sc, flags) + assert(outdata, errdata) + end) + end, { + files = public_sourcefiles, + changed = target:is_rebuilt() or not os.isfile(header), + }) + end + end, { jobgraph = true }) +end) + -- define rule: swift.build rule("swift.build") set_sourcekinds("sc") @@ -27,10 +186,11 @@ rule("swift.build") target:add("scflags", "-parse-as-library") end + local modulename = target:values("swift.modulename") or target:name() + target:add("scflags", "-module-name", modulename, {force = true}) -- we use swift-frontend to support multiple modules -- @see https://github.com/xmake-io/xmake/issues/3916 if target:has_tool("sc", "swift_frontend") then - target:add("scflags", "-module-name", target:name(), {force = true}) local sourcebatch = target:sourcebatches()["swift.build"] if sourcebatch then for _, sourcefile in ipairs(sourcebatch.sourcefiles) do @@ -43,6 +203,9 @@ rule("swift.build") -- define rule: swift rule("swift") + -- add interop rules + add_deps("swift.interop") + -- add build rules add_deps("swift.build") diff --git a/xmake/toolchains/xcode/load_watchos.lua b/xmake/toolchains/xcode/load_watchos.lua index e3deebb8a..99fc12313 100644 --- a/xmake/toolchains/xcode/load_watchos.lua +++ b/xmake/toolchains/xcode/load_watchos.lua @@ -49,6 +49,7 @@ function main(toolchain) toolchain:add("scflags", format("-target %s-apple-ios%s", arch, target_minver) , "-sdk " .. xcode_sysroot) toolchain:add("scshflags", format("-target %s-apple-ios%s", arch, target_minver) , "-sdk " .. xcode_sysroot) toolchain:add("scldflags", format("-target %s-apple-ios%s", arch, target_minver) , "-sdk " .. xcode_sysroot) + toolchain:add("scarflags", format("-target %s-apple-ios%s", arch, target_minver) , "-sdk " .. xcode_sysroot) toolchain:add("scshflags", "-emit-library") toolchain:add("scarflags", "-emit-library", "-static") |
