summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2025-12-03 22:37:53 +0800
committerruki <[email protected]>2025-12-03 22:37:53 +0800
commitea947a6740898e512bd0d805b9ab5735fec691db (patch)
treeabe7453725f4a13b064c032f12ccdc35ac9165b8
parent605ce1f6bcfa8bcbe1a1f8151361f2539fb09727 (diff)
add flang support
-rw-r--r--xmake/modules/core/tools/flang.lua103
-rw-r--r--xmake/modules/core/tools/flang/has_flags.lua116
-rw-r--r--xmake/modules/detect/tools/find_flang.lua55
-rw-r--r--xmake/toolchains/flang/xmake.lua56
4 files changed, 330 insertions, 0 deletions
diff --git a/xmake/modules/core/tools/flang.lua b/xmake/modules/core/tools/flang.lua
new file mode 100644
index 000000000..2b0661e24
--- /dev/null
+++ b/xmake/modules/core/tools/flang.lua
@@ -0,0 +1,103 @@
+--!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, Xmake Open Source Community.
+--
+-- @author ruki
+-- @file flang.lua
+--
+
+-- inherit clang (flang is part of LLVM)
+inherit("clang")
+import("core.base.option")
+import("core.language.language")
+
+-- init it
+function init(self)
+
+ -- init super
+ _super.init(self)
+
+ -- init shflags
+ self:set("fcshflags", "-shared")
+
+ -- add -fPIC for shared
+ if not self:is_plat("windows", "mingw") then
+ self:add("fcshflags", "-fPIC")
+ self:add("shared.fcflags", "-fPIC")
+ end
+
+ -- init flags map to filter unsupported C/C++ flags
+ self:set("mapflags",
+ {
+ -- visibility flags (not supported by Fortran)
+ ["-fvisibility=.*"] = ""
+ })
+end
+
+-- make the symbol flag
+-- Fortran doesn't support visibility flags, only debug symbols
+function nf_symbol(self, level)
+ local kind = self:kind()
+ if language.sourcekinds()[kind] then
+ local maps = {
+ debug = "-g"
+ }
+ return maps[level]
+ elseif kind == "ld" or kind == "sh" then
+ -- we need to add `-g` to linker to generate pdb symbol file for clang on windows
+ if level == "debug" and self:is_plat("windows") then
+ return "-g"
+ end
+ end
+end
+
+-- make the link arguments list
+-- flang doesn't support -install_name, so we don't add it
+function linkargv(self, objectfiles, targetkind, targetfile, flags, opt)
+ opt = opt or {}
+
+ -- init arguments
+ local argv = table.join("-o", targetfile, objectfiles, flags)
+ if is_host("windows") and not opt.rawargs then
+ argv = winos.cmdargv(argv, {escape = true})
+ end
+ return self:program(), argv
+end
+
+-- link the target file
+--
+-- maybe we need to use os.vrunv() to show link output when enable verbose information
+-- @see https://github.com/xmake-io/xmake/discussions/2916
+--
+function link(self, objectfiles, targetkind, targetfile, flags, opt)
+ opt = opt or {}
+
+ -- enable linker output?
+ local target = opt.target
+ local linker_output = option.get("verbose")
+ if linker_output == nil and target and target.policy and target:policy("build.linker.output") then
+ linker_output = true
+ end
+
+ os.mkdir(path.directory(targetfile))
+
+ local program, argv = linkargv(self, objectfiles, targetkind, targetfile, flags, opt)
+ if linker_output then
+ os.execv(program, argv, {envs = self:runenvs(), shell = opt.shell})
+ else
+ os.vrunv(program, argv, {envs = self:runenvs(), shell = opt.shell})
+ end
+end
+
diff --git a/xmake/modules/core/tools/flang/has_flags.lua b/xmake/modules/core/tools/flang/has_flags.lua
new file mode 100644
index 000000000..68f6ad726
--- /dev/null
+++ b/xmake/modules/core/tools/flang/has_flags.lua
@@ -0,0 +1,116 @@
+--!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, Xmake Open Source Community.
+--
+-- @author ruki
+-- @file has_flags.lua
+--
+
+-- imports
+import("core.cache.detectcache")
+import("core.language.language")
+
+-- is linker?
+function _islinker(flags, opt)
+
+ -- the flags is "-Wl,<arg>" or "-Xlinker <arg>"?
+ local flags_str = table.concat(flags, " ")
+ if flags_str:startswith("-Wl,") or flags_str:startswith("-Xlinker ") then
+ return true
+ end
+
+ -- the tool kind is ld or sh?
+ 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(program, argv, opt)
+ local errors = nil
+ return try { function () os.runv(program, argv, opt); return true end, catch { function (errs) errors = (errs or ""):trim() end }}, errors
+end
+
+-- attempt to check it from the argument list
+function _check_from_arglist(flags, opt, islinker)
+
+ -- only for compiler
+ if islinker or #flags > 1 then
+ return
+ end
+
+ -- make cache key
+ local key = "core.tools.flang.has_flags"
+
+ -- make flags key
+ local flagskey = opt.program .. "_" .. (opt.programver or "")
+
+ -- get all flags from argument list
+ local allflags = detectcache:get2(key, flagskey)
+ if not allflags then
+
+ -- get argument list
+ allflags = {}
+ local arglist = os.iorunv(opt.program, {"--help"}, {envs = opt.envs})
+ if arglist then
+ for arg in arglist:gmatch("%s+(%-[%-%a%d]+)%s+") do
+ allflags[arg] = true
+ end
+ end
+
+ -- save cache
+ detectcache:set2(key, flagskey, allflags)
+ end
+ return allflags[flags[1]]
+end
+
+-- try running to check flags
+function _check_try_running(flags, opt, islinker)
+
+ -- make an stub source file
+ local sourcefile = path.join(os.tmpdir(), "detect", "flang_has_flags.f90")
+ if not os.isfile(sourcefile) then
+ io.writefile(sourcefile, "program hello\n print *, \"Hello World!\"\nend program hello")
+ end
+
+ -- check flags for linker
+ if islinker then
+ return _try_running(opt.program, table.join(flags, "-o", os.tmpfile(), sourcefile), opt)
+ end
+
+ -- check flags for compiler
+ -- @note we cannot use os.nuldev() as the output file, maybe run failed for some flags, e.g. --coverage
+ return _try_running(opt.program, table.join(flags, "-S", "-o", os.tmpfile(), sourcefile), opt)
+end
+
+-- has_flags(flags)?
+--
+-- @param opt the argument options, e.g. {toolname = "", program = "", programver = "", toolkind = "[fc|fcld|fcsh]"}
+--
+-- @return true or false
+--
+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, islinker) then
+ return true
+ end
+
+ -- try running to check it
+ return _check_try_running(flags, opt, islinker)
+end
+
diff --git a/xmake/modules/detect/tools/find_flang.lua b/xmake/modules/detect/tools/find_flang.lua
new file mode 100644
index 000000000..2f29b2952
--- /dev/null
+++ b/xmake/modules/detect/tools/find_flang.lua
@@ -0,0 +1,55 @@
+--!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, Xmake Open Source Community.
+--
+-- @author ruki
+-- @file find_flang.lua
+--
+
+-- imports
+import("lib.detect.find_program")
+import("lib.detect.find_programver")
+
+-- find flang
+--
+-- @param opt the argument options, e.g. {version = true}
+--
+-- @return program, version
+--
+-- @code
+--
+-- local flang = find_flang()
+-- local flang, version = find_flang({program = "flang", version = true})
+--
+-- @endcode
+--
+function main(opt)
+
+ -- init options
+ opt = opt or {}
+
+ -- find program
+ local program = find_program(opt.program or "flang", opt)
+
+ -- find program version
+ local version = nil
+ if program and opt and opt.version then
+ version = find_programver(program, opt)
+ end
+
+ -- ok?
+ return program, version
+end
+
diff --git a/xmake/toolchains/flang/xmake.lua b/xmake/toolchains/flang/xmake.lua
new file mode 100644
index 000000000..72eb45258
--- /dev/null
+++ b/xmake/toolchains/flang/xmake.lua
@@ -0,0 +1,56 @@
+--!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, Xmake Open Source Community.
+--
+-- @author ruki
+-- @file xmake.lua
+--
+
+-- define toolchain
+toolchain("flang")
+
+ -- set homepage
+ set_homepage("https://flang.llvm.org/")
+ set_description("LLVM Fortran Compiler")
+
+ -- mark as standalone toolchain
+ set_kind("standalone")
+
+ -- set toolset
+ set_toolset("fc", "$(env FC)", "flang")
+ set_toolset("fcld", "$(env FC)", "flang")
+ set_toolset("fcsh", "$(env FC)", "flang")
+ set_toolset("ar", "llvm-ar", "ar")
+
+ -- on check
+ on_check(function (toolchain)
+ return import("lib.detect.find_tool")("flang", {program = "flang"})
+ end)
+
+ -- on load
+ on_load(function (toolchain)
+ local march
+ if toolchain:is_arch("x86_64", "x64", "arm64") then
+ march = "-m64"
+ elseif toolchain:is_arch("i386", "x86", "i686") then
+ march = "-m32"
+ end
+ if march then
+ toolchain:add("fcflags", march)
+ toolchain:add("fcshflags", march)
+ toolchain:add("fcldflags", march)
+ end
+ end)
+