Skip to content

Instantly share code, notes, and snippets.

@marler8997
Last active June 9, 2022 16:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marler8997/d1e8d54fc3966fbcd619a137ed4dd1f7 to your computer and use it in GitHub Desktop.
Save marler8997/d1e8d54fc3966fbcd619a137ed4dd1f7 to your computer and use it in GitHub Desktop.
Add Zig to your CMake Project

First add your build.zig file to your project source directory. Then add these 2 files alongside each other wherever you keep your cmake include files:

Zig.cmake:

execute_process(
    COMMAND ${CMAKE_CURRENT_LIST_DIR}/install-zig
    OUTPUT_VARIABLE ZIG_EXE
    RESULT_VARIABLE INSTALL_ZIG_EXIT_CODE
)
if (NOT INSTALL_ZIG_EXIT_CODE EQUAL "0")
    message(FATAL_ERROR "install-zig failed")
endif()
add_custom_target(zigbuild
    COMMAND "${ZIG_EXE}" build --prefix ${CMAKE_CURRENT_BINARY_DIR}
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
    DEPENDS ${PROJECT_SOURCE_DIR}/build.zig
)

install-zig:

#!/usr/bin/env python3
# TODO: add windows support
import os
import sys
import fcntl
import shutil
import subprocess

ZIG_VERSION = "0.10.0-dev.2463+b095aa698"
ZIG_INSTALL_PATH = os.path.join(os.getenv("HOME"), ".zig-cmake")

def eprint(*args, **kwargs):
    print(*args, file=sys.stderr, **kwargs)

def run(*args, **kwargs):
    eprint("[RUN] " + subprocess.list2cmdline(*args))
    sys.stdout.flush()
    return subprocess.check_call(*args, **kwargs)

def download(url, filename):
    tmp_filename = filename + ".downloading"
    if os.path.exists(tmp_filename):
        os.remove(tmp_filename)
    run(["curl", url, "--output", tmp_filename])
    os.rename(tmp_filename, filename)

def get_zig_platform():
    import platform
    if sys.platform.startswith("linux"):
        return "linux-x86_64"
    if sys.platform.startswith("darwin"):
        if platform.processor().startswith("arm"):
            return "macos-aarch64"
        return "x86_64"
    sys.exit("unknown platform '{}'".format(sys.platform))

def main():
    ZIG_INSTALL_PATH = os.path.join(os.getenv("HOME"), ".zig-cmake", "zig")
    if not os.path.exists(ZIG_INSTALL_PATH):
        os.makedirs(ZIG_INSTALL_PATH)

    lock_file_path = os.path.join(ZIG_INSTALL_PATH, ".lock")
    lock_file = open(lock_file_path, "w")
    fcntl.flock(lock_file.fileno(), fcntl.LOCK_EX)

    version_install_path = os.path.join(ZIG_INSTALL_PATH, ZIG_VERSION)
    if not os.path.exists(version_install_path):
        zig_platform = get_zig_platform()
        archive_root_basename = "zig-" + zig_platform + "-" + ZIG_VERSION
        tar_basename = archive_root_basename + ".tar.xz"
        tar_path = os.path.join(ZIG_INSTALL_PATH, tar_basename)
        download("https://ziglang.org/builds/" + tar_basename, tar_path)

        extract_root_dir = os.path.join(ZIG_INSTALL_PATH, archive_root_basename)
        if os.path.exists(extract_root_dir):
            shutil.rmtree(extract_root_dir)
        run(["tar", "-C", ZIG_INSTALL_PATH, "-xf", tar_path])
        os.remove(tar_path)
        os.rename(extract_root_dir, version_install_path)
    print(os.path.join(version_install_path, "zig"), end='')

main()

Then you can include the Zig.cmake file and declare zig output dependencies via:

include(Zig)
# let cmake know what files we use from zigbuild
add_custom_command(
    DEPENDS zigbuild
    OUTPUT
        ${CMAKE_CURRENT_BINARY_DIR}/PUT_YOUR_ZIG_OUT_FILES_HERE
)

Also remember to add your zig output files as dependencies to any other cmake component.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment