diff options
| author | ruki <[email protected]> | 2025-12-03 22:37:53 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2025-12-03 22:37:53 +0800 |
| commit | ea947a6740898e512bd0d805b9ab5735fec691db (patch) | |
| tree | abe7453725f4a13b064c032f12ccdc35ac9165b8 | |
| parent | 605ce1f6bcfa8bcbe1a1f8151361f2539fb09727 (diff) | |
add flang support
| -rw-r--r-- | xmake/modules/core/tools/flang.lua | 103 | ||||
| -rw-r--r-- | xmake/modules/core/tools/flang/has_flags.lua | 116 | ||||
| -rw-r--r-- | xmake/modules/detect/tools/find_flang.lua | 55 | ||||
| -rw-r--r-- | xmake/toolchains/flang/xmake.lua | 56 |
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) + |
