Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,6 @@ compile_commands.json
*.mod.c
Module.symvers
modules.order

# ai
.claude
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ gdc The GNU D Compiler (GDC)
gfortran GNU Fortran Programming Language Compiler
flang LLVM Fortran Compiler
zig Zig Programming Language Compiler
zigcc Use zig cc/c++ as C/C++ Compiler
sdcc Small Device C Compiler
cuda CUDA Toolkit (nvcc, nvc, nvc++, nvfortran)
ndk Android NDK
Expand Down
1 change: 1 addition & 0 deletions README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ gdc The GNU D Compiler (GDC)
gfortran GNU Fortran Programming Language Compiler
flang LLVM Fortran Compiler
zig Zig Programming Language Compiler
zigcc Use zig cc/c++ as C/C++ Compiler
sdcc Small Device C Compiler
cuda CUDA Toolkit (nvcc, nvc, nvc++, nvfortran)
ndk Android NDK
Expand Down
2 changes: 1 addition & 1 deletion tests/projects/c++/console_zig_cxx/xmake.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ add_requires("zig")
target("test")
set_kind("binary")
add_files("src/*.cpp")
set_toolchains("@zig")
set_toolchains("zig@zigcc")


2 changes: 1 addition & 1 deletion tests/projects/zig/console_c_call_zig/xmake.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ target("demo")
set_kind("binary")
add_files("src/*.c")
add_files("src/*.zig")
set_toolchains("@zig", {zigcc = false})
set_toolchains("@zig")

62 changes: 62 additions & 0 deletions xmake/modules/private/utils/toolchain.lua
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,68 @@ function get_sanitizer_flags(target, opt)
return result
end

-- get zig target
function get_zig_target(toolchain)
local zig_version = toolchain:config("zig_version")

-- get target from cross only for cross-compilation
-- @see https://github.com/xmake-io/xmake/issues/7180
local target
if not target and toolchain:is_cross() then
target = toolchain:cross()
end

-- get target from arch
if not target then
local arch
if toolchain:is_arch("arm64", "arm64-v8a") then
arch = "aarch64"
elseif toolchain:is_arch("arm", "armv7") then
arch = "arm"
elseif toolchain:is_arch("i386", "x86") then
if zig_version and semver.compare(zig_version, "0.11") >= 0 then
arch = "x86"
else
arch = "i386"
end
elseif toolchain:is_arch("riscv64") then
arch = "riscv64"
elseif toolchain:is_arch("loong64") then
arch = "loongarch64"
elseif toolchain:is_arch("mips.*") then
arch = toolchain:arch()
elseif toolchain:is_arch("ppc64") then
arch = "powerpc64"
elseif toolchain:is_arch("ppc") then
arch = "powerpc"
elseif toolchain:is_arch("s390x") then
arch = "s390x"
else
arch = "x86_64"
end

if toolchain:is_plat("cross") then
-- xmake f -p cross --toolchain=zig --cross=mips64el-linux-gnuabi64
elseif toolchain:is_plat("macosx") then
--@see https://github.com/ziglang/zig/issues/14226
target = arch .. "-macos-none"
elseif toolchain:is_plat("linux") then
if arch == "arm" then
target = "arm-linux-gnueabi"
elseif arch == "mips64" or arch == "mips64el" then
target = arch .. "-linux-gnuabi64"
else
target = arch .. "-linux-gnu"
end
elseif toolchain:is_plat("windows") then
target = arch .. "-windows-msvc"
elseif toolchain:is_plat("mingw") then
target = arch .. "-windows-gnu"
end
end
return target
end

-- check if the file is a c++ header file extension
function is_cxx_headerext(extension)
-- prioritize .h* extensions to filter out most cases quickly
Expand Down
107 changes: 2 additions & 105 deletions xmake/toolchains/zig/xmake.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,12 @@

-- define toolchain
toolchain("zig")
set_kind("standalone")
set_homepage("https://ziglang.org/")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The set_kind("standalone") declaration has been removed. Since the zig toolchain can still be used as a standalone toolchain for Zig language projects (as seen in the test cases), it seems this declaration should be kept for clarity and correctness, similar to other language toolchains like dlang, rust, etc. Please consider adding it back.

    set_kind("standalone")
    set_homepage("https://ziglang.org/")

set_description("Zig Programming Language Compiler")

on_check(function (toolchain)
import("lib.detect.find_tool")

-- @see https://github.com/xmake-io/xmake/issues/5610
function _setup_zigcc_wrapper(zig)
local script_suffix = is_host("windows") and ".cmd" or ""
for _, tool in ipairs({"cc", "c++", "ar", "ranlib", "lib", "ld.lld", "lld-link", "wasm-ld", "objcopy", "dlltool", "rc"}) do
local wrapper_path = path.join(os.tmpdir(), "zigcc", tool) .. script_suffix
if not os.isfile(wrapper_path) then
if is_host("windows") then
io.writefile(wrapper_path, ("@echo off\n\"%s\" %s %%*"):format(zig, tool))
else
io.writefile(wrapper_path, ("#!/bin/bash\nexec \"%s\" %s \"$@\""):format(zig, tool))
os.runv("chmod", {"+x", wrapper_path})
end
end
if (tool == "cc" or tool == "c++") and wrapper_path then
wrapper_path = "zig_cc@" .. wrapper_path
end
toolchain:config_set("toolset_" .. tool, wrapper_path)
end
end

local paths = {}
for _, package in ipairs(toolchain:packages()) do
local envs = package:envs()
Expand All @@ -69,105 +48,23 @@ toolchain("zig")
end
end
if zig then
_setup_zigcc_wrapper(zig)
toolchain:config_set("zig", zig)
toolchain:config_set("zig_version", zig_version)
return true
end
end)

on_load(function (toolchain)
import("core.base.semver")
import("private.utils.toolchain", {alias = "toolchain_utils"})

-- set toolset
-- we patch target to `zig cc` to fix has_flags. see https://github.com/xmake-io/xmake/issues/955#issuecomment-766929692
local zig = toolchain:config("zig") or "zig"
local zig_version = toolchain:config("zig_version")
if toolchain:config("zigcc") ~= false then
-- we can use `set_toolchains("zig", {zigcc = false})` to disable zigcc
-- @see https://github.com/xmake-io/xmake/issues/3251
toolchain:set("toolset", "cc", toolchain:config("toolset_cc"))
toolchain:set("toolset", "cxx", toolchain:config("toolset_c++"))
toolchain:set("toolset", "ld", toolchain:config("toolset_c++"))
toolchain:set("toolset", "sh", toolchain:config("toolset_c++"))
toolchain:set("toolset", "ar", toolchain:config("toolset_ar"))
toolchain:set("toolset", "ranlib", toolchain:config("toolset_ranlib"))
toolchain:set("toolset", "lib", toolchain:config("toolset_lib"))
toolchain:set("toolset", "ld.lld", toolchain:config("toolset_ld.lld"))
toolchain:set("toolset", "lld-link", toolchain:config("toolset_lld-link"))
toolchain:set("toolset", "wasm-ld", toolchain:config("toolset_wasm-ld"))
toolchain:set("toolset", "objcopy", toolchain:config("toolset_objcopy"))
toolchain:set("toolset", "as", toolchain:config("toolset_cc"))
toolchain:set("toolset", "dlltool", toolchain:config("toolset_dlltool"))
toolchain:set("toolset", "mrc", toolchain:config("toolset_rc"))
end
toolchain:set("toolset", "zc", zig)
toolchain:set("toolset", "zcar", zig)
toolchain:set("toolset", "zcld", zig)
toolchain:set("toolset", "zcsh", zig)

-- get target from cross only for cross-compilation
-- @see https://github.com/xmake-io/xmake/issues/7180
local target
if not target and toolchain:is_cross() then
target = toolchain:cross()
end

-- get target from arch
if not target then
local arch
if toolchain:is_arch("arm64", "arm64-v8a") then
arch = "aarch64"
elseif toolchain:is_arch("arm", "armv7") then
arch = "arm"
elseif toolchain:is_arch("i386", "x86") then
if zig_version and semver.compare(zig_version, "0.11") >= 0 then
arch = "x86"
else
arch = "i386"
end
elseif toolchain:is_arch("riscv64") then
arch = "riscv64"
elseif toolchain:is_arch("loong64") then
arch = "loongarch64"
elseif toolchain:is_arch("mips.*") then
arch = toolchain:arch()
elseif toolchain:is_arch("ppc64") then
arch = "powerpc64"
elseif toolchain:is_arch("ppc") then
arch = "powerpc"
elseif toolchain:is_arch("s390x") then
arch = "s390x"
else
arch = "x86_64"
end

if toolchain:is_plat("cross") then
-- xmake f -p cross --toolchain=zig --cross=mips64el-linux-gnuabi64
elseif toolchain:is_plat("macosx") then
--@see https://github.com/ziglang/zig/issues/14226
target = arch .. "-macos-none"
elseif toolchain:is_plat("linux") then
if arch == "arm" then
target = "arm-linux-gnueabi"
elseif arch == "mips64" or arch == "mips64el" then
target = arch .. "-linux-gnuabi64"
else
target = arch .. "-linux-gnu"
end
elseif toolchain:is_plat("windows") then
target = arch .. "-windows-msvc"
elseif toolchain:is_plat("mingw") then
target = arch .. "-windows-gnu"
end
end

-- set target flags
local target = toolchain_utils.get_zig_target(toolchain)
if target then
toolchain:add("asflags", "-target", target)
toolchain:add("cxflags", "-target", target)
toolchain:add("shflags", "-target", target)
toolchain:add("ldflags", "-target", target)
toolchain:add("zcflags", "-target", target)
toolchain:add("zcldflags", "-target", target)
toolchain:add("zcshflags", "-target", target)
Expand Down
106 changes: 106 additions & 0 deletions xmake/toolchains/zigcc/xmake.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
--!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("zigcc")
set_kind("standalone")
set_homepage("https://ziglang.org/")
set_description("Use zig cc/c++ as C/C++ Compiler")

on_check(function (toolchain)
import("lib.detect.find_tool")

-- @see https://github.com/xmake-io/xmake/issues/5610
local function _setup_zigcc_wrapper(zig)
local script_suffix = is_host("windows") and ".cmd" or ""
for _, tool in ipairs({"cc", "c++", "ar", "ranlib", "lib", "ld.lld", "lld-link", "wasm-ld", "objcopy", "dlltool", "rc"}) do
local wrapper_path = path.join(os.tmpdir(), "zigcc", tool) .. script_suffix
if not os.isfile(wrapper_path) then
if is_host("windows") then
io.writefile(wrapper_path, ("@echo off\n\"%s\" %s %%*"):format(zig, tool))
else
io.writefile(wrapper_path, ("#!/bin/bash\nexec \"%s\" %s \"$@\""):format(zig, tool))
os.runv("chmod", {"+x", wrapper_path})
end
end
Comment on lines +34 to +42
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

The _setup_zigcc_wrapper function creates wrapper scripts in a predictable, shared temporary directory (os.tmpdir()/zigcc). On multi-user systems (like Linux), an attacker can pre-create these files with malicious content. Since the code checks for the existence of the file before writing (if not os.isfile(wrapper_path)), it will not overwrite an existing malicious script. This allows an attacker to execute arbitrary code with the privileges of any user who runs xmake with the zigcc toolchain.

To remediate this, use a more secure location for the wrapper scripts, such as a directory within the user's home directory or a project-specific directory. If a temporary directory must be used, ensure it is unique to the user and has restricted permissions (e.g., 0700).

if (tool == "cc" or tool == "c++") and wrapper_path then
wrapper_path = "zig_cc@" .. wrapper_path
end
toolchain:config_set("toolset_" .. tool, wrapper_path)
end
end

local paths = {}
for _, package in ipairs(toolchain:packages()) do
local envs = package:envs()
if envs then
table.join2(paths, envs.PATH)
end
end
local sdkdir = toolchain:sdkdir()
if sdkdir then
table.insert(paths, sdkdir)
end

local zig = get_config("zc")
local zig_version
if not zig then
zig = find_tool("zig", {force = true, version = true, paths = paths})
if zig and zig.program then
zig_version = zig.version
zig = zig.program
end
end
if zig then
_setup_zigcc_wrapper(zig)
toolchain:config_set("zig", zig)
toolchain:config_set("zig_version", zig_version)
return true
end
Comment on lines +50 to +76
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic for finding the zig executable is duplicated in xmake/toolchains/zig/xmake.lua and xmake/toolchains/zigcc/xmake.lua. To improve maintainability and avoid code duplication, this logic could be extracted into a new utility function in xmake/modules/private/utils/toolchain.lua.

end)

on_load(function (toolchain)
import("private.utils.toolchain", {alias = "toolchain_utils"})

-- set toolset
-- we patch target to `zig cc` to fix has_flags. see https://github.com/xmake-io/xmake/issues/955#issuecomment-766929692
toolchain:set("toolset", "cc", toolchain:config("toolset_cc"))
toolchain:set("toolset", "cxx", toolchain:config("toolset_c++"))
toolchain:set("toolset", "ld", toolchain:config("toolset_c++"))
toolchain:set("toolset", "sh", toolchain:config("toolset_c++"))
toolchain:set("toolset", "ar", toolchain:config("toolset_ar"))
toolchain:set("toolset", "ranlib", toolchain:config("toolset_ranlib"))
toolchain:set("toolset", "lib", toolchain:config("toolset_lib"))
toolchain:set("toolset", "ld.lld", toolchain:config("toolset_ld.lld"))
toolchain:set("toolset", "lld-link", toolchain:config("toolset_lld-link"))
toolchain:set("toolset", "wasm-ld", toolchain:config("toolset_wasm-ld"))
toolchain:set("toolset", "objcopy", toolchain:config("toolset_objcopy"))
toolchain:set("toolset", "as", toolchain:config("toolset_cc"))
toolchain:set("toolset", "dlltool", toolchain:config("toolset_dlltool"))
toolchain:set("toolset", "mrc", toolchain:config("toolset_rc"))

local target = toolchain_utils.get_zig_target(toolchain)
if target then
toolchain:add("asflags", "-target", target)
toolchain:add("cxflags", "-target", target)
toolchain:add("shflags", "-target", target)
toolchain:add("ldflags", "-target", target)
end
end)
Loading