Add TCC project (as a library)
This commit is contained in:
264
packages/tcc/src/root.zig
Normal file
264
packages/tcc/src/root.zig
Normal file
@@ -0,0 +1,264 @@
|
||||
pub const std = @import("std");
|
||||
|
||||
pub const State = opaque {
|
||||
pub fn init() !*State {
|
||||
return import.tcc_new() orelse error.OutOfMemory;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *State) void {
|
||||
import.tcc_delete(self);
|
||||
}
|
||||
|
||||
/// Set TCC's private include and library path. Equivalent to
|
||||
/// `CONFIG_TCCDIR` define or `-B` option.
|
||||
pub fn setLibPath(self: *State, path: [*:0]const u8) void {
|
||||
import.tcc_set_lib_path(self, path);
|
||||
}
|
||||
|
||||
pub fn setErrorCallback(self: *State, context: ?*anyopaque, callback: ?*const ErrorCallbackFn) void {
|
||||
import.tcc_set_error_func(self, context, callback);
|
||||
}
|
||||
|
||||
/// Set TCC options using command line arguments syntax. You can specify
|
||||
/// multiple options.
|
||||
pub fn setOptions(self: *State, options: [*:0]const u8) void {
|
||||
import.tcc_set_options(self, options);
|
||||
}
|
||||
|
||||
// --- PREPROCESSOR ---
|
||||
|
||||
/// Add include path. Equivalent to `-I` option.
|
||||
pub fn addIncludePath(self: *State, path: [*:0]const u8) void {
|
||||
_ = import.tcc_add_include_path(self, path);
|
||||
}
|
||||
|
||||
/// Add system include path. Equivalent to `-isystem` option.
|
||||
pub fn addSystemIncludePath(self: *State, path: [*:0]const u8) void {
|
||||
_ = import.tcc_add_sysinclude_path(self, path);
|
||||
}
|
||||
|
||||
/// Add a preprocessor define. Defaults to `1`.
|
||||
pub fn addDefine(self: *State, symbol: [*:0]const u8, value: ?[*:0]const u8) void {
|
||||
import.tcc_define_symbol(self, symbol, value);
|
||||
}
|
||||
|
||||
/// Remove a preprocessor define, if exists.
|
||||
pub fn removeDefine(self: *State, symbol: [*:0]const u8) void {
|
||||
import.tcc_undefine_symbol(self, symbol);
|
||||
}
|
||||
|
||||
// --- COMPILING ---
|
||||
|
||||
/// Add a file (C source file, assembly, object file, library, DLL or an ld
|
||||
/// script).
|
||||
pub fn addFile(self: *State, filename: ?[*:0]const u8) !void {
|
||||
const result = import.tcc_add_file(self, filename);
|
||||
if (result < 0) return error.FileError;
|
||||
}
|
||||
|
||||
/// Compile a C source string.
|
||||
pub fn compileString(self: *State, source: [*:0]const u8) !void {
|
||||
const result = import.tcc_compile_string(self, source);
|
||||
if (result < 0) return error.CompileError;
|
||||
}
|
||||
|
||||
// --- LINKING COMMANDS ---
|
||||
|
||||
/// Set output type. Must be called before any compilation.
|
||||
pub fn setOutputType(self: *State, output_type: OutputType) void {
|
||||
_ = import.tcc_set_output_type(self, output_type);
|
||||
}
|
||||
|
||||
/// Add library search path. Equivalent to `-L` option.
|
||||
pub fn addLibraryPath(self: *State, path: [*:0]const u8) void {
|
||||
_ = import.tcc_add_library_path(self, path);
|
||||
}
|
||||
|
||||
/// Link library. Equivalent to `-l` option. The library name should be the
|
||||
/// same as if provided to the command line option, i.e. with "lib" prefix
|
||||
/// and the extension possibly omitted.
|
||||
pub fn addLibrary(self: *State, library: ?[*:0]const u8) !void {
|
||||
const result = import.tcc_add_library(self, library);
|
||||
if (result < 0) return error.AddLibraryError;
|
||||
}
|
||||
|
||||
/// Add a symbol to the compiled program (like an extern function or data).
|
||||
pub fn addSymbol(self: *State, name: [*:0]const u8, value: ?*anyopaque) void {
|
||||
_ = import.tcc_add_symbol(self, name, value);
|
||||
}
|
||||
|
||||
/// Output an executable, library or object file. Must not call
|
||||
/// `tcc_relocate` beforehand.
|
||||
pub fn outputFile(self: *State, filename: [*:0]const u8) !void {
|
||||
const result = import.tcc_output_file(self, filename);
|
||||
if (result < 0) return error.OutputFileError;
|
||||
}
|
||||
|
||||
/// Link and run `main` function and return its value. Must not call
|
||||
/// `tcc_relocate` beforehand.
|
||||
pub fn run(self: *State, args: [:null][*:0]u8) c_int {
|
||||
return import.tcc_run(self, @intCast(args.len), args.ptr);
|
||||
}
|
||||
|
||||
/// Do all relocations necessary before calling `State.getSymbol`. Use
|
||||
/// internal memory management.
|
||||
pub fn relocateAuto(self: *State) !void {
|
||||
const result = import.tcc_relocate(self, RELOCATE_AUTO);
|
||||
if (result < 0) return error.RelocateError;
|
||||
}
|
||||
|
||||
/// Do all relocations necessary before calling `State.getSymbol`. Use
|
||||
/// provided `allocator` for allocating the result.
|
||||
///
|
||||
/// If the function returns without an error, the user is responsible for
|
||||
/// calling `allocator.free` on the returned memory to free it.
|
||||
pub fn relocateAlloc(self: *State, allocator: std.mem.Allocator) ![]const u8 {
|
||||
const size = import.tcc_relocate(self, null);
|
||||
if (size < 0) return error.RelocateError;
|
||||
|
||||
const memory = try allocator.alignedAlloc(u8, .fromByteUnits(16), @intCast(size));
|
||||
errdefer allocator.free(memory);
|
||||
|
||||
const result = import.tcc_relocate(self, memory.ptr);
|
||||
if (result < 0) return error.RelocateError;
|
||||
|
||||
return memory;
|
||||
}
|
||||
|
||||
/// Get a pointer to a symbol value. Returns `null` if not found.
|
||||
pub fn getSymbol(self: *State, name: [*:0]const u8) ?*anyopaque {
|
||||
return import.tcc_get_symbol(self, name);
|
||||
}
|
||||
};
|
||||
|
||||
pub const ErrorCallbackFn = fn (context: ?*anyopaque, message: ?[*:0]const u8) callconv(.c) void;
|
||||
|
||||
pub const OutputType = enum(c_int) {
|
||||
/// Output will be run in memory (default).
|
||||
memory = 1,
|
||||
/// Executable file.
|
||||
exe = 2,
|
||||
/// Dynamic library.
|
||||
dll = 3,
|
||||
/// Object file.
|
||||
obj = 4,
|
||||
/// Only preprocess (used internally).
|
||||
preprocess = 5,
|
||||
};
|
||||
|
||||
/// Magic constant for `tcc_relocate`.
|
||||
pub const RELOCATE_AUTO: ?*anyopaque = @ptrFromInt(1);
|
||||
|
||||
pub const import = struct {
|
||||
/// Create a new TCC compilation context.
|
||||
pub extern fn tcc_new() ?*State;
|
||||
|
||||
/// Free a TCC compilation context.
|
||||
pub extern fn tcc_delete(state: *State) void;
|
||||
|
||||
/// Set CONFIG_TCCDIR at runtime.
|
||||
pub extern fn tcc_set_lib_path(state: *State, path: [*:0]const u8) void;
|
||||
|
||||
/// Set error/warning display callback.
|
||||
pub extern fn tcc_set_error_func(state: *State, context: ?*anyopaque, callback: ?*const ErrorCallbackFn) void;
|
||||
|
||||
/// Set options as from command line (multiple supported).
|
||||
pub extern fn tcc_set_options(state: *State, options: [*:0]const u8) void;
|
||||
|
||||
// --- PREPROCESSOR ---
|
||||
|
||||
/// Add include path.
|
||||
///
|
||||
/// NOTE Always returns `0`.
|
||||
pub extern fn tcc_add_include_path(state: *State, path: [*:0]const u8) c_int;
|
||||
|
||||
/// Add in system include path.
|
||||
///
|
||||
/// NOTE Always returns `0`.
|
||||
pub extern fn tcc_add_sysinclude_path(state: *State, path: [*:0]const u8) c_int;
|
||||
|
||||
/// Define preprocessor symbol `symbol`. Can put optional value.
|
||||
///
|
||||
/// NOTE Defaults to `1`.
|
||||
pub extern fn tcc_define_symbol(state: *State, symbol: [*:0]const u8, value: ?[*:0]const u8) void;
|
||||
|
||||
/// Undefine preprocess symbol `symbol`.
|
||||
pub extern fn tcc_undefine_symbol(state: *State, symbol: [*:0]const u8) void;
|
||||
|
||||
// --- COMPILING ---
|
||||
|
||||
/// Add a file (C file, dll, object, library, ld script). Return -1 if error.
|
||||
///
|
||||
/// NOTE Returns only either `0` or `-1`.
|
||||
pub extern fn tcc_add_file(state: *State, filename: [*:0]const u8) c_int;
|
||||
|
||||
/// Compile a string containing a C source. Return -1 if error.
|
||||
///
|
||||
/// NOTE Returns only either `0` or `-1`.
|
||||
pub extern fn tcc_compile_string(state: *State, source: [*:0]const u8) c_int;
|
||||
|
||||
// --- LINKING COMMANDS ---
|
||||
|
||||
/// Set output type. MUST BE CALLED before any compilation.
|
||||
///
|
||||
/// NOTE Always returns `0`.
|
||||
pub extern fn tcc_set_output_type(state: *State, output_type: OutputType) c_int;
|
||||
|
||||
/// Equivalent to -Lpath option.
|
||||
///
|
||||
/// NOTE Always returns `0`.
|
||||
pub extern fn tcc_add_library_path(state: *State, path: [*:0]const u8) c_int;
|
||||
|
||||
/// The library name is the same as the argument of the `-l` option.
|
||||
pub extern fn tcc_add_library(state: *State, library: [*:0]const u8) c_int;
|
||||
|
||||
/// Add a symbol to the compiled program.
|
||||
///
|
||||
/// NOTE Always returns `0`.
|
||||
pub extern fn tcc_add_symbol(state: *State, name: [*:0]const u8, value: ?*anyopaque) c_int;
|
||||
|
||||
/// Output an executable, library or object file. DO NOT call tcc_relocate()
|
||||
/// before.
|
||||
pub extern fn tcc_output_file(state: *State, filename: [*:0]const u8) c_int;
|
||||
|
||||
/// Link and run main() function and return its value. DO NOT call
|
||||
/// tcc_relocate() before.
|
||||
pub extern fn tcc_run(state: *State, argc: c_int, argv: [*:null][*:0]u8) c_int;
|
||||
|
||||
/// Do all relocations (needed before using tcc_get_symbol()).
|
||||
///
|
||||
/// Possible values for `ptr`:
|
||||
/// * `RELOCATE_AUTO`: Allocate and manage memory internally
|
||||
/// * `null`: return required memory size for the step below
|
||||
/// * memory address: copy code to memory passed by the caller
|
||||
///
|
||||
/// Returns -1 if error.
|
||||
pub extern fn tcc_relocate(state: *State, ptr: ?*anyopaque) c_int;
|
||||
|
||||
/// Return symbol value or NULL if not found.
|
||||
pub extern fn tcc_get_symbol(state: *State, name: [*:0]const u8) ?*anyopaque;
|
||||
};
|
||||
|
||||
test {
|
||||
const add = &struct {
|
||||
pub fn add(a: c_int, b: c_int) callconv(.c) c_int {
|
||||
return a + b;
|
||||
}
|
||||
}.add;
|
||||
|
||||
var tcc: *State = try .init();
|
||||
tcc.setOutputType(.memory);
|
||||
tcc.setOptions("-nostdlib");
|
||||
try tcc.compileString(
|
||||
\\int add(int a, int b);
|
||||
\\int add_one(int a) { return add(a, 1); }
|
||||
);
|
||||
|
||||
tcc.addSymbol("add", @constCast(add));
|
||||
try tcc.relocateAuto();
|
||||
const add_one: *const fn (a: c_int) callconv(.c) c_int = @ptrCast(tcc.getSymbol("add_one").?);
|
||||
|
||||
try std.testing.expectEqual(0, add_one(-1));
|
||||
try std.testing.expectEqual(1, add_one(0));
|
||||
try std.testing.expectEqual(2, add_one(1));
|
||||
}
|
||||
Reference in New Issue
Block a user