Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove cImport #20643

Closed
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ This produces a `zig2` executable in the current working directory. This is a
therefore lacking these features:
- Release mode optimizations
- aarch64 machine code backend
- `@cImport` / `zig translate-c`
- `zig translate-c`
- Ability to compile C files
- Ability to compile assembly files
- [Some ELF linking features](https://github.com/ziglang/zig/issues/17749)
Expand Down
14 changes: 1 addition & 13 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -467,18 +467,6 @@ pub fn build(b: *std.Build) !void {
.max_rss = 1 * 1024 * 1024 * 1024,
}));

test_step.dependOn(tests.addModuleTests(b, .{
.test_filters = test_filters,
.root_src = "test/c_import.zig",
.name = "c-import",
.desc = "Run the @cImport tests",
.optimize_modes = optimization_modes,
.include_paths = &.{"test/c_import"},
.skip_single_threaded = true,
.skip_non_native = skip_non_native,
.skip_libc = skip_libc,
}));

test_step.dependOn(tests.addModuleTests(b, .{
.test_filters = test_filters,
.root_src = "lib/compiler_rt.zig",
Expand Down Expand Up @@ -1282,7 +1270,7 @@ fn generateLangRef(b: *std.Build) std.Build.LazyPath {
// in a temporary directory
"--cache-root", b.cache_root.path orelse ".",
});
cmd.addArgs(&.{ "--zig-lib-dir", b.fmt("{}", .{b.graph.zig_lib_directory}) });
// cmd.addArgs(&.{ "--zig-lib-dir", b.fmt("{}", .{b.graph.zig_lib_directory}) });
cmd.addArgs(&.{"-i"});
cmd.addFileArg(b.path(b.fmt("doc/langref/{s}", .{entry.name})));

Expand Down
149 changes: 13 additions & 136 deletions doc/langref.html.in
Original file line number Diff line number Diff line change
Expand Up @@ -995,7 +995,7 @@

{#header_open|Local Variables#}
<p>
Local variables occur inside {#link|Functions#}, {#link|comptime#} blocks, and {#link|@cImport#} blocks.
Local variables occur inside {#link|Functions#} and {#link|comptime#} blocks.
</p>
<p>
When a local variable is {#syntax#}const{#endsyntax#}, it means that after initialization, the variable's
Expand Down Expand Up @@ -3742,17 +3742,17 @@ void do_a_thing(struct Foo *foo) {

<p>
{#syntax#}usingnamespace{#endsyntax#} has an important use case when organizing the public
API of a file or package. For example, one might have <code class="file">c.zig</code> with all of the
{#link|C imports|Import from C Header File#}:
API of a file or package. For example, one might have <code class="file">c.zig</code> with C definitions
based on the OS:
</p>
{#syntax_block|zig|c.zig#}
pub usingnamespace @cImport({
@cInclude("epoxy/gl.h");
@cInclude("GLFW/glfw3.h");
@cDefine("STBI_ONLY_PNG", "");
@cDefine("STBI_NO_STDIO", "");
@cInclude("stb_image.h");
});
pub usingnamespace switch(native_os) {
.linux => @import("c/linux.zig"),
.windows => @import("c/windows.zig"),
.macos => @import("c/darwin.zig"),
.wasi => wasi,
else => struct {},
};
{#end_syntax_block#}
<p>
The above example demonstrates using {#syntax#}pub{#endsyntax#} to qualify the
Expand Down Expand Up @@ -4409,62 +4409,6 @@ comptime {

{#header_close#}

{#header_open|@cDefine#}
<pre>{#syntax#}@cDefine(comptime name: []const u8, value) void{#endsyntax#}</pre>
<p>
This function can only occur inside {#syntax#}@cImport{#endsyntax#}.
</p>
<p>
This appends <code>#define $name $value</code> to the {#syntax#}@cImport{#endsyntax#}
temporary buffer.
</p>
<p>
To define without a value, like this:
</p>
<pre><code class="c">#define _GNU_SOURCE</code></pre>
<p>
Use the void value, like this:
</p>
<pre>{#syntax#}@cDefine("_GNU_SOURCE", {}){#endsyntax#}</pre>
{#see_also|Import from C Header File|@cInclude|@cImport|@cUndef|void#}
{#header_close#}
{#header_open|@cImport#}
<pre>{#syntax#}@cImport(expression) type{#endsyntax#}</pre>
<p>
This function parses C code and imports the functions, types, variables,
and compatible macro definitions into a new empty struct type, and then
returns that type.
</p>
<p>
{#syntax#}expression{#endsyntax#} is interpreted at compile time. The builtin functions
{#syntax#}@cInclude{#endsyntax#}, {#syntax#}@cDefine{#endsyntax#}, and {#syntax#}@cUndef{#endsyntax#} work
within this expression, appending to a temporary buffer which is then parsed as C code.
</p>
<p>
Usually you should only have one {#syntax#}@cImport{#endsyntax#} in your entire application, because it saves the compiler
from invoking clang multiple times, and prevents inline functions from being duplicated.
</p>
<p>
Reasons for having multiple {#syntax#}@cImport{#endsyntax#} expressions would be:
</p>
<ul>
<li>To avoid a symbol collision, for example if foo.h and bar.h both <code>#define CONNECTION_COUNT</code></li>
<li>To analyze the C code with different preprocessor defines</li>
</ul>
{#see_also|Import from C Header File|@cInclude|@cDefine|@cUndef#}
{#header_close#}
{#header_open|@cInclude#}
<pre>{#syntax#}@cInclude(comptime path: []const u8) void{#endsyntax#}</pre>
<p>
This function can only occur inside {#syntax#}@cImport{#endsyntax#}.
</p>
<p>
This appends <code>#include &lt;$path&gt;\n</code> to the {#syntax#}c_import{#endsyntax#}
temporary buffer.
</p>
{#see_also|Import from C Header File|@cImport|@cDefine|@cUndef#}
{#header_close#}

{#header_open|@clz#}
<pre>{#syntax#}@clz(operand: anytype) anytype{#endsyntax#}</pre>
<p>{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type or an integer vector type.</p>
Expand Down Expand Up @@ -4598,18 +4542,6 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
{#see_also|@clz|@popCount#}
{#header_close#}

{#header_open|@cUndef#}
<pre>{#syntax#}@cUndef(comptime name: []const u8) void{#endsyntax#}</pre>
<p>
This function can only occur inside {#syntax#}@cImport{#endsyntax#}.
</p>
<p>
This appends <code>#undef $name</code> to the {#syntax#}@cImport{#endsyntax#}
temporary buffer.
</p>
{#see_also|Import from C Header File|@cImport|@cDefine|@cInclude#}
{#header_close#}

{#header_open|@cVaArg#}
<pre>{#syntax#}@cVaArg(operand: *std.builtin.VaList, comptime T: type) T{#endsyntax#}</pre>
<p>
Expand Down Expand Up @@ -6456,35 +6388,6 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
</p>
{#see_also|Primitive Types#}
{#header_close#}
{#header_open|Import from C Header File#}
<p>
The {#syntax#}@cImport{#endsyntax#} builtin function can be used
to directly import symbols from <code class="file">.h</code> files:
</p>
{#code|cImport_builtin.zig#}

<p>
The {#syntax#}@cImport{#endsyntax#} function takes an expression as a parameter.
This expression is evaluated at compile-time and is used to control
preprocessor directives and include multiple <code class="file">.h</code> files:
</p>
{#syntax_block|zig|@cImport Expression#}
const builtin = @import("builtin");

const c = @cImport({
@cDefine("NDEBUG", builtin.mode == .ReleaseFast);
if (something) {
@cDefine("_GNU_SOURCE", {});
}
@cInclude("stdlib.h");
if (something) {
@cUndef("_GNU_SOURCE");
}
@cInclude("soundio.h");
});
{#end_syntax_block#}
{#see_also|@cImport|@cInclude|@cDefine|@cUndef|@import#}
{#header_close#}

{#header_open|C Translation CLI#}
<p>
Expand Down Expand Up @@ -6544,41 +6447,15 @@ $ zig translate-c -cflags -fshort-enums -- varycflags.h|grep -B1 do_something
pub const enum_FOO = u8;
pub extern fn do_something(foo: enum_FOO) c_int;{#end_shell_samp#}
{#header_close#}
{#header_open|@cImport vs translate-c#}
<p>{#syntax#}@cImport{#endsyntax#} and <kbd>zig translate-c</kbd> use the same underlying
C translation functionality, so on a technical level they are equivalent. In practice,
{#syntax#}@cImport{#endsyntax#} is useful as a way to quickly and easily access numeric constants, typedefs,
and record types without needing any extra setup. If you need to pass {#link|cflags|Using -target and -cflags#}
to clang, or if you would like to edit the translated code, it is recommended to use
<kbd>zig translate-c</kbd> and save the results to a file. Common reasons for editing
the generated code include: changing {#syntax#}anytype{#endsyntax#} parameters in function-like macros to more
specific types; changing {#syntax#}[*c]T{#endsyntax#} pointers to {#syntax#}[*]T{#endsyntax#} or
{#syntax#}*T{#endsyntax#} pointers for improved type safety; and
{#link|enabling or disabling runtime safety|@setRuntimeSafety#} within specific functions.
</p>
{#header_close#}
{#see_also|Targets|C Type Primitives|Pointers|C Pointers|Import from C Header File|@cInclude|@cImport|@setRuntimeSafety#}
{#see_also|Targets|C Type Primitives|Pointers|C Pointers|@setRuntimeSafety#}
{#header_close#}
{#header_open|C Translation Caching#}
<p>
The C translation feature (whether used via <kbd>zig translate-c</kbd> or
{#syntax#}@cImport{#endsyntax#}) integrates with the Zig caching system. Subsequent runs with
The C translation feature integrates with the Zig caching system. Subsequent runs with
the same source file, target, and cflags will use the cache instead of repeatedly translating
the same code.
</p>
<p>
To see where the cached files are stored when compiling code that uses {#syntax#}@cImport{#endsyntax#},
use the <kbd>--verbose-cimport</kbd> flag:
</p>
{#code|verbose_cimport_flag.zig#}

<p>
<code class="file">cimport.h</code> contains the file to translate (constructed from calls to
{#syntax#}@cInclude{#endsyntax#}, {#syntax#}@cDefine{#endsyntax#}, and {#syntax#}@cUndef{#endsyntax#}),
<code class="file">cimport.h.d</code> is the list of file dependencies, and
<code class="file">cimport.zig</code> contains the translated output.
</p>
{#see_also|Import from C Header File|C Translation CLI|@cInclude|@cImport#}
{#see_also|C Translation CLI#}
{#header_close#}
{#header_open|Translation failures#}
<p>
Expand Down
11 changes: 0 additions & 11 deletions doc/langref/cImport_builtin.zig

This file was deleted.

11 changes: 0 additions & 11 deletions doc/langref/verbose_cimport_flag.zig

This file was deleted.

68 changes: 1 addition & 67 deletions lib/std/zig/AstGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2788,7 +2788,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
.mul_add,
.max,
.min,
.c_import,
.@"resume",
.@"await",
.ret_err_value_code,
Expand Down Expand Up @@ -8981,7 +8980,6 @@ fn typeOf(
var typeof_scope = gz.makeSubBlock(scope);
typeof_scope.is_comptime = false;
typeof_scope.is_typeof = true;
typeof_scope.c_import = false;
defer typeof_scope.unstack();

const ty_expr = try reachableExpr(&typeof_scope, &typeof_scope.base, .{ .rl = .none }, args[0], node);
Expand Down Expand Up @@ -9080,8 +9078,7 @@ fn builtinCall(
const builtin_name = tree.tokenSlice(builtin_token);

// We handle the different builtins manually because they have different semantics depending
// on the function. For example, `@as` and others participate in result location semantics,
// and `@cImport` creates a special scope that collects a .c source code text buffer.
// on the function. For example `@as` and others participate in result location semantics.
// Also, some builtins have a variable number of parameters.

const info = BuiltinFn.list.get(builtin_name) orelse {
Expand Down Expand Up @@ -9159,7 +9156,6 @@ fn builtinCall(
.bit_cast => return bitCast( gz, scope, ri, node, params[0]),
.TypeOf => return typeOf( gz, scope, ri, node, params),
.union_init => return unionInit(gz, scope, ri, node, params),
.c_import => return cImport( gz, scope, node, params[0]),
.min => return minMax( gz, scope, ri, node, params, .min),
.max => return minMax( gz, scope, ri, node, params, .max),
// zig fmt: on
Expand Down Expand Up @@ -9449,9 +9445,6 @@ fn builtinCall(
.bit_offset_of => return offsetOf(gz, scope, ri, node, params[0], params[1], .bit_offset_of),
.offset_of => return offsetOf(gz, scope, ri, node, params[0], params[1], .offset_of),

.c_undef => return simpleCBuiltin(gz, scope, ri, node, params[0], .c_undef),
.c_include => return simpleCBuiltin(gz, scope, ri, node, params[0], .c_include),

.cmpxchg_strong => return cmpxchg(gz, scope, ri, node, params, 1),
.cmpxchg_weak => return cmpxchg(gz, scope, ri, node, params, 0),
// zig fmt: on
Expand All @@ -9474,17 +9467,6 @@ fn builtinCall(
});
return rvalue(gz, ri, result, node);
},
.c_define => {
if (!gz.c_import) return gz.astgen.failNode(node, "C define valid only inside C import block", .{});
const name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[0]);
const value = try comptimeExpr(gz, scope, .{ .rl = .none }, params[1]);
const result = try gz.addExtendedPayload(.c_define, Zir.Inst.BinNode{
.node = gz.nodeIndexToRelative(node),
.lhs = name,
.rhs = value,
});
return rvalue(gz, ri, result, node);
},

.splat => {
const result_type = try ri.rl.resultTypeForCast(gz, node, builtin_name);
Expand Down Expand Up @@ -9851,24 +9833,6 @@ fn divBuiltin(
return rvalue(gz, ri, result, node);
}

fn simpleCBuiltin(
gz: *GenZir,
scope: *Scope,
ri: ResultInfo,
node: Ast.Node.Index,
operand_node: Ast.Node.Index,
tag: Zir.Inst.Extended,
) InnerError!Zir.Inst.Ref {
const name: []const u8 = if (tag == .c_undef) "C undef" else "C include";
if (!gz.c_import) return gz.astgen.failNode(node, "{s} valid only inside C import block", .{name});
const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, operand_node);
_ = try gz.addExtendedPayload(tag, Zir.Inst.UnNode{
.node = gz.nodeIndexToRelative(node),
.operand = operand,
});
return rvalue(gz, ri, .void_value, node);
}

fn offsetOf(
gz: *GenZir,
scope: *Scope,
Expand Down Expand Up @@ -9918,35 +9882,6 @@ fn shiftOp(
return rvalue(gz, ri, result, node);
}

fn cImport(
gz: *GenZir,
scope: *Scope,
node: Ast.Node.Index,
body_node: Ast.Node.Index,
) InnerError!Zir.Inst.Ref {
const astgen = gz.astgen;
const gpa = astgen.gpa;

if (gz.c_import) return gz.astgen.failNode(node, "cannot nest @cImport", .{});

var block_scope = gz.makeSubBlock(scope);
block_scope.is_comptime = true;
block_scope.c_import = true;
defer block_scope.unstack();

const block_inst = try gz.makeBlockInst(.c_import, node);
const block_result = try fullBodyExpr(&block_scope, &block_scope.base, .{ .rl = .none }, body_node);
_ = try gz.addUnNode(.ensure_result_used, block_result, node);
if (!gz.refIsNoReturn(block_result)) {
_ = try block_scope.addBreak(.break_inline, block_inst, .void_value);
}
try block_scope.setBlockBody(block_inst);
// block_scope unstacked now, can add new instructions to gz
try gz.instructions.append(gpa, block_inst);

return block_inst.toRef();
}

fn overflowArithmetic(
gz: *GenZir,
scope: *Scope,
Expand Down Expand Up @@ -11943,7 +11878,6 @@ const GenZir = struct {
return .{
.is_comptime = gz.is_comptime,
.is_typeof = gz.is_typeof,
.c_import = gz.c_import,
.decl_node_index = gz.decl_node_index,
.decl_line = gz.decl_line,
.parent = scope,
Expand Down
Loading
Loading