mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-14 03:25:50 +00:00
cmake: add ghostty_vt_add_target() for cross-compilation (#12212)
Add a ghostty_vt_add_target() CMake function that lets downstream projects build libghostty-vt for a specific Zig target triple. The function encapsulates zig discovery, build-type-to-optimize mapping, the zig build invocation, and output path conventions so consumers do not need to duplicate any of that logic. It creates named IMPORTED targets (e.g. ghostty-vt-static-linux-amd64) that work alongside the existing native ghostty-vt and ghostty-vt-static targets. The build-type mapping is factored into a shared _GHOSTTY_ZIG_OPT_FLAG variable used by both the native build and the new function. A new example/c-vt-cmake-cross/ demonstrates end-to-end cross- compilation using zig cc as the C compiler, auto-detecting a cross target based on the host OS.
This commit is contained in:
5
.github/workflows/test.yml
vendored
5
.github/workflows/test.yml
vendored
@@ -278,6 +278,11 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
dir: ${{ fromJSON(needs.list-examples.outputs.cmake) }}
|
||||
exclude:
|
||||
# Cross-compilation with zig cc requires a single-config
|
||||
# generator (Makefiles/Ninja). The Windows CI uses Visual
|
||||
# Studio which always uses MSVC and ignores CMAKE_C_COMPILER.
|
||||
- dir: c-vt-cmake-cross
|
||||
name: Example ${{ matrix.dir }} (Windows)
|
||||
runs-on: namespace-profile-ghostty-windows
|
||||
timeout-minutes: 45
|
||||
|
||||
159
CMakeLists.txt
159
CMakeLists.txt
@@ -44,8 +44,27 @@
|
||||
# target_link_libraries(myapp PRIVATE ghostty-vt::ghostty-vt) # shared
|
||||
# target_link_libraries(myapp PRIVATE ghostty-vt::ghostty-vt-static) # static
|
||||
#
|
||||
# See dist/cmake/README.md for more details and example/c-vt-cmake/ for a
|
||||
# complete working example.
|
||||
# Cross-compilation
|
||||
# -------------------
|
||||
#
|
||||
# For building libghostty-vt for a non-native Zig target (e.g. cross-
|
||||
# compiling), use the ghostty_vt_add_target() function after FetchContent:
|
||||
#
|
||||
# FetchContent_MakeAvailable(ghostty)
|
||||
# ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu)
|
||||
#
|
||||
# target_link_libraries(myapp PRIVATE ghostty-vt-static-linux-amd64) # static
|
||||
# target_link_libraries(myapp PRIVATE ghostty-vt-linux-amd64) # shared
|
||||
#
|
||||
# This handles zig discovery, build-type-to-optimize mapping, and output
|
||||
# path conventions internally. Extra flags can be forwarded with ZIG_FLAGS:
|
||||
#
|
||||
# ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu
|
||||
# ZIG_FLAGS -Dsimd=false)
|
||||
#
|
||||
# See dist/cmake/README.md for more details, example/c-vt-cmake/ for a
|
||||
# complete working example, and example/c-vt-cmake-cross/ for a cross-
|
||||
# compilation example.
|
||||
|
||||
cmake_minimum_required(VERSION 3.19)
|
||||
project(ghostty-vt VERSION 0.1.0 LANGUAGES C)
|
||||
@@ -54,15 +73,22 @@ project(ghostty-vt VERSION 0.1.0 LANGUAGES C)
|
||||
|
||||
set(GHOSTTY_ZIG_BUILD_FLAGS "" CACHE STRING "Additional flags to pass to zig build")
|
||||
|
||||
# Map CMake build types to Zig optimization levels.
|
||||
# Map CMake build types to Zig optimization levels. The result is stored in
|
||||
# _GHOSTTY_ZIG_OPT_FLAG so both the native build and ghostty_vt_add_target()
|
||||
# can reuse it without duplicating the mapping logic.
|
||||
set(_GHOSTTY_ZIG_OPT_FLAG "")
|
||||
if(CMAKE_BUILD_TYPE)
|
||||
string(TOUPPER "${CMAKE_BUILD_TYPE}" _bt)
|
||||
if(_bt STREQUAL "RELEASE" OR _bt STREQUAL "MINSIZEREL" OR _bt STREQUAL "RELWITHDEBINFO")
|
||||
list(APPEND GHOSTTY_ZIG_BUILD_FLAGS "-Doptimize=ReleaseFast")
|
||||
set(_GHOSTTY_ZIG_OPT_FLAG "-Doptimize=ReleaseFast")
|
||||
endif()
|
||||
unset(_bt)
|
||||
endif()
|
||||
|
||||
if(_GHOSTTY_ZIG_OPT_FLAG)
|
||||
list(APPEND GHOSTTY_ZIG_BUILD_FLAGS "${_GHOSTTY_ZIG_OPT_FLAG}")
|
||||
endif()
|
||||
|
||||
# --- Find Zig ----------------------------------------------------------------
|
||||
|
||||
find_program(ZIG_EXECUTABLE zig REQUIRED)
|
||||
@@ -229,3 +255,128 @@ install(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/ghostty-vt-config-version.cmake"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ghostty-vt"
|
||||
)
|
||||
|
||||
# --- Cross-compilation helper ------------------------------------------------
|
||||
#
|
||||
# For downstream projects that need to build libghostty-vt for a specific
|
||||
# Zig target triple. For native builds, use the IMPORTED targets above
|
||||
# (ghostty-vt, ghostty-vt-static) directly.
|
||||
#
|
||||
# Usage (in a downstream CMakeLists.txt after FetchContent_MakeAvailable):
|
||||
#
|
||||
# ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu)
|
||||
#
|
||||
# Creates:
|
||||
# ghostty-vt-static-linux-amd64 (IMPORTED STATIC library)
|
||||
# ghostty-vt-linux-amd64 (IMPORTED SHARED library)
|
||||
#
|
||||
# Optional ZIG_FLAGS to pass additional flags to zig build:
|
||||
#
|
||||
# ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu
|
||||
# ZIG_FLAGS -Dsimd=false)
|
||||
|
||||
function(ghostty_vt_add_target)
|
||||
cmake_parse_arguments(PARSE_ARGV 0 _GVT "" "NAME;ZIG_TARGET" "ZIG_FLAGS")
|
||||
|
||||
if(NOT _GVT_NAME)
|
||||
message(FATAL_ERROR "ghostty_vt_add_target: NAME is required")
|
||||
endif()
|
||||
if(NOT _GVT_ZIG_TARGET)
|
||||
message(FATAL_ERROR "ghostty_vt_add_target: ZIG_TARGET is required")
|
||||
endif()
|
||||
|
||||
set(_src_dir "${CMAKE_CURRENT_FUNCTION_LIST_DIR}")
|
||||
set(_prefix "${CMAKE_CURRENT_BINARY_DIR}/ghostty-${_GVT_NAME}")
|
||||
|
||||
# Build flags
|
||||
set(_flags
|
||||
-Demit-lib-vt
|
||||
-Dtarget=${_GVT_ZIG_TARGET}
|
||||
--prefix "${_prefix}"
|
||||
)
|
||||
|
||||
# Default to ReleaseFast when no build type is set. Debug builds enable
|
||||
# UBSan in zig, and the sanitizer runtime is not available for all
|
||||
# cross-compilation targets.
|
||||
if(_GHOSTTY_ZIG_OPT_FLAG)
|
||||
list(APPEND _flags "${_GHOSTTY_ZIG_OPT_FLAG}")
|
||||
else()
|
||||
list(APPEND _flags "-Doptimize=ReleaseFast")
|
||||
endif()
|
||||
|
||||
if(_GVT_ZIG_FLAGS)
|
||||
list(APPEND _flags ${_GVT_ZIG_FLAGS})
|
||||
endif()
|
||||
|
||||
# Output paths
|
||||
set(_include_dir "${_prefix}/include")
|
||||
|
||||
if(_GVT_ZIG_TARGET MATCHES "windows")
|
||||
set(_static_lib "${_prefix}/lib/ghostty-vt-static.lib")
|
||||
set(_shared_lib "${_prefix}/bin/ghostty-vt.dll")
|
||||
set(_implib "${_prefix}/lib/ghostty-vt.lib")
|
||||
elseif(_GVT_ZIG_TARGET MATCHES "darwin|macos")
|
||||
set(_static_lib "${_prefix}/lib/libghostty-vt.a")
|
||||
set(_shared_lib "${_prefix}/lib/libghostty-vt.0.1.0.dylib")
|
||||
else()
|
||||
set(_static_lib "${_prefix}/lib/libghostty-vt.a")
|
||||
set(_shared_lib "${_prefix}/lib/libghostty-vt.so.0.1.0")
|
||||
endif()
|
||||
|
||||
file(MAKE_DIRECTORY "${_include_dir}")
|
||||
|
||||
# Custom command: invoke zig build
|
||||
add_custom_command(
|
||||
OUTPUT "${_static_lib}" "${_shared_lib}"
|
||||
COMMAND "${ZIG_EXECUTABLE}" build ${_flags}
|
||||
WORKING_DIRECTORY "${_src_dir}"
|
||||
COMMENT "Building libghostty-vt for ${_GVT_ZIG_TARGET}..."
|
||||
USES_TERMINAL
|
||||
)
|
||||
|
||||
set(_build_target "zig_build_lib_vt_${_GVT_NAME}")
|
||||
add_custom_target(${_build_target} ALL
|
||||
DEPENDS "${_static_lib}" "${_shared_lib}"
|
||||
)
|
||||
|
||||
# Static target
|
||||
set(_static_target "ghostty-vt-static-${_GVT_NAME}")
|
||||
add_library(${_static_target} STATIC IMPORTED GLOBAL)
|
||||
set_target_properties(${_static_target} PROPERTIES
|
||||
IMPORTED_LOCATION "${_static_lib}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${_include_dir}"
|
||||
INTERFACE_COMPILE_DEFINITIONS "GHOSTTY_STATIC"
|
||||
)
|
||||
if(_GVT_ZIG_TARGET MATCHES "windows")
|
||||
set_target_properties(${_static_target} PROPERTIES
|
||||
INTERFACE_LINK_LIBRARIES "c++;ntdll;kernel32"
|
||||
)
|
||||
else()
|
||||
set_target_properties(${_static_target} PROPERTIES
|
||||
INTERFACE_LINK_LIBRARIES "c++"
|
||||
)
|
||||
endif()
|
||||
add_dependencies(${_static_target} ${_build_target})
|
||||
|
||||
# Shared target
|
||||
set(_shared_target "ghostty-vt-${_GVT_NAME}")
|
||||
add_library(${_shared_target} SHARED IMPORTED GLOBAL)
|
||||
set_target_properties(${_shared_target} PROPERTIES
|
||||
IMPORTED_LOCATION "${_shared_lib}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${_include_dir}"
|
||||
)
|
||||
if(_GVT_ZIG_TARGET MATCHES "windows")
|
||||
set_target_properties(${_shared_target} PROPERTIES
|
||||
IMPORTED_IMPLIB "${_implib}"
|
||||
)
|
||||
elseif(_GVT_ZIG_TARGET MATCHES "darwin|macos")
|
||||
set_target_properties(${_shared_target} PROPERTIES
|
||||
IMPORTED_SONAME "@rpath/libghostty-vt.0.dylib"
|
||||
)
|
||||
else()
|
||||
set_target_properties(${_shared_target} PROPERTIES
|
||||
IMPORTED_SONAME "libghostty-vt.so.0"
|
||||
)
|
||||
endif()
|
||||
add_dependencies(${_shared_target} ${_build_target})
|
||||
endfunction()
|
||||
|
||||
74
dist/cmake/GhosttyZigCompiler.cmake
vendored
Normal file
74
dist/cmake/GhosttyZigCompiler.cmake
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
# GhosttyZigCompiler.cmake — set up zig cc as a cross compiler
|
||||
#
|
||||
# Provides ghostty_zig_compiler() which configures zig cc / zig c++ as
|
||||
# the C/CXX compiler for a given Zig target triple. It creates small
|
||||
# wrapper scripts (shell on Unix, .cmd on Windows) and sets the
|
||||
# following CMake variables in the caller's scope:
|
||||
#
|
||||
# CMAKE_C_COMPILER, CMAKE_CXX_COMPILER,
|
||||
# CMAKE_C_COMPILER_FORCED, CMAKE_CXX_COMPILER_FORCED,
|
||||
# CMAKE_SYSTEM_NAME, CMAKE_EXECUTABLE_SUFFIX (Windows only)
|
||||
#
|
||||
# This file is self-contained with no dependencies on the ghostty
|
||||
# source tree. Copy it into your project and include it directly.
|
||||
# It cannot be consumed via FetchContent because it must run before
|
||||
# project(), but FetchContent_MakeAvailable triggers project()
|
||||
# internally.
|
||||
#
|
||||
# Must be called BEFORE project() — CMake reads the compiler variables
|
||||
# at project() time and won't re-detect after that.
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# cmake_minimum_required(VERSION 3.19)
|
||||
#
|
||||
# include(cmake/GhosttyZigCompiler.cmake)
|
||||
# ghostty_zig_compiler(ZIG_TARGET x86_64-linux-gnu)
|
||||
#
|
||||
# project(myapp LANGUAGES C CXX)
|
||||
#
|
||||
# FetchContent_MakeAvailable(ghostty)
|
||||
# ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu)
|
||||
# target_link_libraries(myapp PRIVATE ghostty-vt-static-linux-amd64)
|
||||
#
|
||||
# See example/c-vt-cmake-cross/ for a complete working example.
|
||||
|
||||
include_guard(GLOBAL)
|
||||
|
||||
function(ghostty_zig_compiler)
|
||||
cmake_parse_arguments(PARSE_ARGV 0 _GZC "" "ZIG_TARGET" "")
|
||||
|
||||
if(NOT _GZC_ZIG_TARGET)
|
||||
message(FATAL_ERROR "ghostty_zig_compiler: ZIG_TARGET is required")
|
||||
endif()
|
||||
|
||||
find_program(_GZC_ZIG zig REQUIRED)
|
||||
|
||||
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
|
||||
set(_cc "${CMAKE_CURRENT_BINARY_DIR}/zig-cc.cmd")
|
||||
set(_cxx "${CMAKE_CURRENT_BINARY_DIR}/zig-cxx.cmd")
|
||||
file(WRITE "${_cc}" "@\"${_GZC_ZIG}\" cc -target ${_GZC_ZIG_TARGET} %*\n")
|
||||
file(WRITE "${_cxx}" "@\"${_GZC_ZIG}\" c++ -target ${_GZC_ZIG_TARGET} %*\n")
|
||||
else()
|
||||
set(_cc "${CMAKE_CURRENT_BINARY_DIR}/zig-cc")
|
||||
set(_cxx "${CMAKE_CURRENT_BINARY_DIR}/zig-c++")
|
||||
file(WRITE "${_cc}" "#!/bin/sh\nexec \"${_GZC_ZIG}\" cc -target ${_GZC_ZIG_TARGET} \"$@\"\n")
|
||||
file(WRITE "${_cxx}" "#!/bin/sh\nexec \"${_GZC_ZIG}\" c++ -target ${_GZC_ZIG_TARGET} \"$@\"\n")
|
||||
file(CHMOD "${_cc}" "${_cxx}"
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_COMPILER "${_cc}" PARENT_SCOPE)
|
||||
set(CMAKE_CXX_COMPILER "${_cxx}" PARENT_SCOPE)
|
||||
set(CMAKE_C_COMPILER_FORCED TRUE PARENT_SCOPE)
|
||||
set(CMAKE_CXX_COMPILER_FORCED TRUE PARENT_SCOPE)
|
||||
|
||||
if(_GZC_ZIG_TARGET MATCHES "windows")
|
||||
set(CMAKE_SYSTEM_NAME Windows PARENT_SCOPE)
|
||||
set(CMAKE_EXECUTABLE_SUFFIX ".exe" PARENT_SCOPE)
|
||||
elseif(_GZC_ZIG_TARGET MATCHES "linux")
|
||||
set(CMAKE_SYSTEM_NAME Linux PARENT_SCOPE)
|
||||
elseif(_GZC_ZIG_TARGET MATCHES "darwin|macos")
|
||||
set(CMAKE_SYSTEM_NAME Darwin PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
45
dist/cmake/README.md
vendored
45
dist/cmake/README.md
vendored
@@ -57,11 +57,46 @@ add_executable(myapp main.c)
|
||||
target_link_libraries(myapp PRIVATE ghostty-vt::ghostty-vt)
|
||||
```
|
||||
|
||||
## Files
|
||||
## Cross-compilation
|
||||
|
||||
- `ghostty-vt-config.cmake.in` — template for the CMake package config
|
||||
file installed alongside the library, enabling `find_package()` support.
|
||||
For cross-compiling to a different Zig target triple, use
|
||||
`ghostty_vt_add_target()` after `FetchContent_MakeAvailable`:
|
||||
|
||||
## Example
|
||||
```cmake
|
||||
FetchContent_MakeAvailable(ghostty)
|
||||
ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu)
|
||||
|
||||
See `example/c-vt-cmake/` for a complete working example.
|
||||
add_executable(myapp main.c)
|
||||
target_link_libraries(myapp PRIVATE ghostty-vt-static-linux-amd64)
|
||||
```
|
||||
|
||||
### Using zig cc as the C/CXX compiler
|
||||
|
||||
When cross-compiling, the host C compiler can't link binaries for the
|
||||
target platform. `GhosttyZigCompiler.cmake` provides
|
||||
`ghostty_zig_compiler()` to set up `zig cc` as the C/CXX compiler for
|
||||
the cross target. It creates wrapper scripts (shell on Unix, `.cmd` on
|
||||
Windows) and configures `CMAKE_C_COMPILER`, `CMAKE_CXX_COMPILER`, and
|
||||
`CMAKE_SYSTEM_NAME`.
|
||||
|
||||
The module is self-contained — copy it into your project (e.g. to
|
||||
`cmake/`) and include it directly. It cannot be consumed via
|
||||
FetchContent because it must run before `project()`, but
|
||||
`FetchContent_MakeAvailable` triggers `project()` internally:
|
||||
|
||||
```cmake
|
||||
cmake_minimum_required(VERSION 3.19)
|
||||
|
||||
include(cmake/GhosttyZigCompiler.cmake)
|
||||
ghostty_zig_compiler(ZIG_TARGET x86_64-linux-gnu)
|
||||
|
||||
project(myapp LANGUAGES C CXX)
|
||||
|
||||
FetchContent_MakeAvailable(ghostty)
|
||||
ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu)
|
||||
|
||||
add_executable(myapp main.c)
|
||||
target_link_libraries(myapp PRIVATE ghostty-vt-static-linux-amd64)
|
||||
```
|
||||
|
||||
See `example/c-vt-cmake-cross/` for a complete working example.
|
||||
|
||||
59
example/c-vt-cmake-cross/CMakeLists.txt
Normal file
59
example/c-vt-cmake-cross/CMakeLists.txt
Normal file
@@ -0,0 +1,59 @@
|
||||
cmake_minimum_required(VERSION 3.19)
|
||||
|
||||
# --- Determine cross-compilation target before project() --------------------
|
||||
#
|
||||
# We need to know the target before project() so we can set up zig cc as the
|
||||
# C/C++ compiler for the cross target.
|
||||
|
||||
# Pick a cross-compilation target: build for a different OS than the host.
|
||||
# Can be overridden with -DZIG_TARGET=... on the command line.
|
||||
if(NOT ZIG_TARGET)
|
||||
# CMAKE_HOST_SYSTEM_PROCESSOR may not be set before project(), so
|
||||
# fall back to `uname -m`.
|
||||
if(CMAKE_HOST_SYSTEM_PROCESSOR)
|
||||
set(_arch "${CMAKE_HOST_SYSTEM_PROCESSOR}")
|
||||
else()
|
||||
execute_process(COMMAND uname -m OUTPUT_VARIABLE _arch OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
endif()
|
||||
if(_arch MATCHES "^(x86_64|AMD64)$")
|
||||
set(_arch "x86_64")
|
||||
elseif(_arch MATCHES "^(aarch64|arm64|ARM64)$")
|
||||
set(_arch "aarch64")
|
||||
endif()
|
||||
|
||||
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
|
||||
set(ZIG_TARGET "${_arch}-windows-gnu")
|
||||
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
|
||||
set(ZIG_TARGET "${_arch}-linux-gnu")
|
||||
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
|
||||
set(ZIG_TARGET "${_arch}-linux-gnu")
|
||||
else()
|
||||
message(FATAL_ERROR
|
||||
"Cannot derive ZIG_TARGET for ${CMAKE_HOST_SYSTEM_NAME}. "
|
||||
"Pass -DZIG_TARGET=... manually.")
|
||||
endif()
|
||||
|
||||
message(STATUS "Cross-compiling for ZIG_TARGET: ${ZIG_TARGET}")
|
||||
endif()
|
||||
|
||||
# --- Set up zig cc as the cross compiler ------------------------------------
|
||||
|
||||
# GhosttyZigCompiler.cmake must be called before project().
|
||||
# Downstream projects would copy this file into their tree; here we
|
||||
# include it directly from the repo.
|
||||
include(../../dist/cmake/GhosttyZigCompiler.cmake)
|
||||
ghostty_zig_compiler(ZIG_TARGET "${ZIG_TARGET}")
|
||||
|
||||
project(c-vt-cmake-cross LANGUAGES C CXX)
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(ghostty
|
||||
GIT_REPOSITORY https://github.com/ghostty-org/ghostty.git
|
||||
GIT_TAG main
|
||||
)
|
||||
FetchContent_MakeAvailable(ghostty)
|
||||
|
||||
ghostty_vt_add_target(NAME cross ZIG_TARGET "${ZIG_TARGET}")
|
||||
|
||||
add_executable(c_vt_cmake_cross src/main.c)
|
||||
target_link_libraries(c_vt_cmake_cross PRIVATE ghostty-vt-static-cross)
|
||||
21
example/c-vt-cmake-cross/README.md
Normal file
21
example/c-vt-cmake-cross/README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# c-vt-cmake-cross
|
||||
|
||||
Demonstrates using `ghostty_vt_add_target()` to cross-compile
|
||||
libghostty-vt with static linking. The target OS is chosen automatically:
|
||||
|
||||
| Host | Target |
|
||||
| ------- | --------------- |
|
||||
| Linux | Windows (MinGW) |
|
||||
| Windows | Linux (glibc) |
|
||||
| macOS | Linux (glibc) |
|
||||
|
||||
Override with `-DZIG_TARGET=...` if needed.
|
||||
|
||||
## Building
|
||||
|
||||
```shell-session
|
||||
cd example/c-vt-cmake-cross
|
||||
cmake -B build -DFETCHCONTENT_SOURCE_DIR_GHOSTTY=../..
|
||||
cmake --build build
|
||||
file build/c_vt_cmake_cross
|
||||
```
|
||||
52
example/c-vt-cmake-cross/src/main.c
Normal file
52
example/c-vt-cmake-cross/src/main.c
Normal file
@@ -0,0 +1,52 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ghostty/vt.h>
|
||||
|
||||
int main() {
|
||||
// Create a terminal with a small grid
|
||||
GhosttyTerminal terminal;
|
||||
GhosttyTerminalOptions opts = {
|
||||
.cols = 80,
|
||||
.rows = 24,
|
||||
.max_scrollback = 0,
|
||||
};
|
||||
GhosttyResult result = ghostty_terminal_new(NULL, &terminal, opts);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
|
||||
// Write some VT-encoded content into the terminal
|
||||
const char *commands[] = {
|
||||
"Hello from a \033[1mCMake\033[0m-built program!\r\n",
|
||||
"Line 2: \033[4munderlined\033[0m text\r\n",
|
||||
"Line 3: \033[31mred\033[0m \033[32mgreen\033[0m \033[34mblue\033[0m\r\n",
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
|
||||
ghostty_terminal_vt_write(terminal, (const uint8_t *)commands[i],
|
||||
strlen(commands[i]));
|
||||
}
|
||||
|
||||
// Format the terminal contents as plain text
|
||||
GhosttyFormatterTerminalOptions fmt_opts =
|
||||
GHOSTTY_INIT_SIZED(GhosttyFormatterTerminalOptions);
|
||||
fmt_opts.emit = GHOSTTY_FORMATTER_FORMAT_PLAIN;
|
||||
fmt_opts.trim = true;
|
||||
|
||||
GhosttyFormatter formatter;
|
||||
result = ghostty_formatter_terminal_new(NULL, &formatter, terminal, fmt_opts);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
|
||||
uint8_t *buf = NULL;
|
||||
size_t len = 0;
|
||||
result = ghostty_formatter_format_alloc(formatter, NULL, &buf, &len);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
|
||||
printf("Plain text (%zu bytes):\n", len);
|
||||
fwrite(buf, 1, len, stdout);
|
||||
printf("\n");
|
||||
|
||||
ghostty_free(NULL, buf, len);
|
||||
ghostty_formatter_free(formatter);
|
||||
ghostty_terminal_free(terminal);
|
||||
return 0;
|
||||
}
|
||||
@@ -279,10 +279,9 @@ fn initLib(
|
||||
|
||||
// For static libraries with vendored SIMD dependencies, combine
|
||||
// all archives into a single fat archive so consumers only need
|
||||
// to link one file. Skip on Windows where ar/libtool aren't available.
|
||||
// to link one file.
|
||||
if (kind == .static and
|
||||
zig.simd_libs.items.len > 0 and
|
||||
target.result.os.tag != .windows)
|
||||
zig.simd_libs.items.len > 0)
|
||||
{
|
||||
var sources: SharedDeps.LazyPathList = .empty;
|
||||
try sources.append(b.allocator, lib.getEmittedBin());
|
||||
@@ -329,26 +328,17 @@ fn combineArchives(
|
||||
return .{ .step = libtool.step, .output = libtool.output };
|
||||
}
|
||||
|
||||
// On non-Darwin, use an MRI script with ar -M to combine archives
|
||||
// directly without extracting. This avoids issues with ar x
|
||||
// producing full-path member names and read-only permissions.
|
||||
const run = RunStep.create(b, "combine-archives ghostty-vt");
|
||||
run.addArgs(&.{
|
||||
"/bin/sh", "-c",
|
||||
\\set -e
|
||||
\\out="$1"; shift
|
||||
\\script="CREATE $out"
|
||||
\\for a in "$@"; do
|
||||
\\ script="$script
|
||||
\\ADDLIB $a"
|
||||
\\done
|
||||
\\script="$script
|
||||
\\SAVE
|
||||
\\END"
|
||||
\\echo "$script" | ar -M
|
||||
,
|
||||
"_",
|
||||
// On non-Darwin, use a build tool that generates an MRI script and
|
||||
// pipes it to `zig ar -M`. This works on all platforms including
|
||||
// Windows (the previous /bin/sh approach did not).
|
||||
const tool = b.addExecutable(.{
|
||||
.name = "combine_archives",
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.path("src/build/combine_archives.zig"),
|
||||
.target = b.graph.host,
|
||||
}),
|
||||
});
|
||||
const run = b.addRunArtifact(tool);
|
||||
const output = run.addOutputFileArg("libghostty-vt.a");
|
||||
for (sources) |source| run.addFileArg(source);
|
||||
|
||||
|
||||
54
src/build/combine_archives.zig
Normal file
54
src/build/combine_archives.zig
Normal file
@@ -0,0 +1,54 @@
|
||||
//! Build tool that combines multiple static archives into a single fat
|
||||
//! archive using an MRI script piped to `zig ar -M`.
|
||||
//!
|
||||
//! MRI scripts require stdin piping (`ar -M < script`), which can't be
|
||||
//! expressed as a single command in the zig build system's RunStep. The
|
||||
//! previous approach used `/bin/sh -c` to do the piping, but that isn't
|
||||
//! available on Windows. This tool handles both the script generation
|
||||
//! and the piping in a single cross-platform executable.
|
||||
//!
|
||||
//! Usage: combine_archives <output.a> <input1.a> [input2.a ...]
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
|
||||
const alloc = gpa.allocator();
|
||||
|
||||
const args = try std.process.argsAlloc(alloc);
|
||||
if (args.len < 3) {
|
||||
std.log.err("usage: combine_archives <output> <input...>", .{});
|
||||
std.process.exit(1);
|
||||
}
|
||||
|
||||
const output_path = args[1];
|
||||
const inputs = args[2..];
|
||||
|
||||
// Build the MRI script.
|
||||
var script: std.ArrayListUnmanaged(u8) = .empty;
|
||||
try script.appendSlice(alloc, "CREATE ");
|
||||
try script.appendSlice(alloc, output_path);
|
||||
try script.append(alloc, '\n');
|
||||
for (inputs) |input| {
|
||||
try script.appendSlice(alloc, "ADDLIB ");
|
||||
try script.appendSlice(alloc, input);
|
||||
try script.append(alloc, '\n');
|
||||
}
|
||||
try script.appendSlice(alloc, "SAVE\nEND\n");
|
||||
|
||||
var child: std.process.Child = .init(&.{ "zig", "ar", "-M" }, alloc);
|
||||
child.stdin_behavior = .Pipe;
|
||||
child.stdout_behavior = .Inherit;
|
||||
child.stderr_behavior = .Inherit;
|
||||
|
||||
try child.spawn();
|
||||
try child.stdin.?.writeAll(script.items);
|
||||
child.stdin.?.close();
|
||||
child.stdin = null;
|
||||
|
||||
const term = try child.wait();
|
||||
if (term.Exited != 0) {
|
||||
std.log.err("zig ar -M exited with code {d}", .{term.Exited});
|
||||
std.process.exit(1);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user