Merge branch 'raulgrell-CastToCVoid'
This commit is contained in:
commit
b92fac329e
@ -7057,6 +7057,61 @@ const c = @cImport({
|
||||
});
|
||||
{#code_end#}
|
||||
{#see_also|@cImport|@cInclude|@cDefine|@cUndef|@import#}
|
||||
{#header_close#}
|
||||
{#header_open|Exporting a C Library#}
|
||||
<p>
|
||||
One of the primary use cases for Zig is exporting a library with the C ABI for other programming languages
|
||||
to call into. The <code>export</code> keyword in front of functions, variables, and types causes them to
|
||||
be part of the library API:
|
||||
</p>
|
||||
<p class="file">mathtest.zig</p>
|
||||
{#code_begin|syntax#}
|
||||
export fn add(a: i32, b: i32) i32 {
|
||||
return a + b;
|
||||
}
|
||||
{#code_end#}
|
||||
<p>To make a shared library:</p>
|
||||
<pre><code class="shell">$ zig build-lib mathtest.zig
|
||||
</code></pre>
|
||||
<p>To make a static library:</p>
|
||||
<pre><code class="shell">$ zig build-lib mathtest.zig --static
|
||||
</code></pre>
|
||||
<p>Here is an example with the {#link|Zig Build System#}:</p>
|
||||
<p class="file">test.c</p>
|
||||
<pre><code class="cpp">// This header is generated by zig from mathtest.zig
|
||||
#include "mathtest.h"
|
||||
#include <assert.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
assert(add(42, 1337) == 1379);
|
||||
return 0;
|
||||
}</code></pre>
|
||||
<p class="file">build.zig</p>
|
||||
{#code_begin|syntax#}
|
||||
const Builder = @import("std").build.Builder;
|
||||
|
||||
pub fn build(b: *Builder) void {
|
||||
const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
|
||||
|
||||
const exe = b.addCExecutable("test");
|
||||
exe.addCompileFlags([][]const u8{"-std=c99"});
|
||||
exe.addSourceFile("test.c");
|
||||
exe.linkLibrary(lib);
|
||||
|
||||
b.default_step.dependOn(&exe.step);
|
||||
|
||||
const run_cmd = b.addCommand(".", b.env_map, [][]const u8{exe.getOutputPath()});
|
||||
run_cmd.step.dependOn(&exe.step);
|
||||
|
||||
const test_step = b.step("test", "Test the program");
|
||||
test_step.dependOn(&run_cmd.step);
|
||||
}
|
||||
{#code_end#}
|
||||
<p class="file">terminal</p>
|
||||
<pre><code class="shell">$ zig build
|
||||
$ ./test
|
||||
$ echo $?
|
||||
0</code></pre>
|
||||
{#header_close#}
|
||||
{#header_open|Mixing Object Files#}
|
||||
<p>
|
||||
|
20
src/ir.cpp
20
src/ir.cpp
@ -60,7 +60,7 @@ enum ConstCastResultId {
|
||||
ConstCastResultIdType,
|
||||
ConstCastResultIdUnresolvedInferredErrSet,
|
||||
ConstCastResultIdAsyncAllocatorType,
|
||||
ConstCastResultIdNullWrapPtr,
|
||||
ConstCastResultIdNullWrapPtr
|
||||
};
|
||||
|
||||
struct ConstCastOnly;
|
||||
@ -8471,9 +8471,9 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
|
||||
if (wanted_type == actual_type)
|
||||
return result;
|
||||
|
||||
// * and [*] can do a const-cast-only to ?* and ?[*], respectively
|
||||
// but not if there is a mutable parent pointer
|
||||
// and not if the pointer is zero bits
|
||||
// *T and [*]T may const-cast-only to ?*U and ?[*]U, respectively
|
||||
// but not if we want a mutable pointer
|
||||
// and not if the actual pointer has zero bits
|
||||
if (!wanted_is_mutable && wanted_type->id == TypeTableEntryIdOptional &&
|
||||
wanted_type->data.maybe.child_type->id == TypeTableEntryIdPointer &&
|
||||
actual_type->id == TypeTableEntryIdPointer && type_has_bits(actual_type))
|
||||
@ -8488,6 +8488,18 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
|
||||
return result;
|
||||
}
|
||||
|
||||
// *T and [*]T can always cast to *c_void
|
||||
if (wanted_type->id == TypeTableEntryIdPointer &&
|
||||
wanted_type->data.pointer.ptr_len == PtrLenSingle &&
|
||||
wanted_type->data.pointer.child_type == g->builtin_types.entry_c_void &&
|
||||
actual_type->id == TypeTableEntryIdPointer &&
|
||||
(!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) &&
|
||||
(!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile))
|
||||
{
|
||||
assert(actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment);
|
||||
return result;
|
||||
}
|
||||
|
||||
// pointer const
|
||||
if (wanted_type->id == TypeTableEntryIdPointer && actual_type->id == TypeTableEntryIdPointer) {
|
||||
ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
|
||||
|
@ -487,12 +487,35 @@ fn MakeType(comptime T: type) type {
|
||||
}
|
||||
|
||||
test "implicit cast from *[N]T to ?[*]T" {
|
||||
var x: ?[*]u16 = null;
|
||||
var y: [4]u16 = [4]u16 {0, 1, 2, 3};
|
||||
var x: ?[*]u16 = null;
|
||||
var y: [4]u16 = [4]u16{ 0, 1, 2, 3 };
|
||||
|
||||
x = &y;
|
||||
assert(std.mem.eql(u16, x.?[0..4], y[0..4]));
|
||||
x.?[0] = 8;
|
||||
y[3] = 6;
|
||||
assert(std.mem.eql(u16, x.?[0..4], y[0..4]));
|
||||
}
|
||||
x = &y;
|
||||
assert(std.mem.eql(u16, x.?[0..4], y[0..4]));
|
||||
x.?[0] = 8;
|
||||
y[3] = 6;
|
||||
assert(std.mem.eql(u16, x.?[0..4], y[0..4]));
|
||||
}
|
||||
|
||||
test "implicit cast from *T to ?*c_void" {
|
||||
var a: u8 = 1;
|
||||
incrementVoidPtrValue(&a);
|
||||
std.debug.assert(a == 2);
|
||||
}
|
||||
|
||||
fn incrementVoidPtrValue(value: ?*c_void) void {
|
||||
@ptrCast(*u8, value.?).* += 1;
|
||||
}
|
||||
|
||||
test "implicit cast from [*]T to ?*c_void" {
|
||||
var a = []u8{ 3, 2, 1 };
|
||||
incrementVoidPtrArray(a[0..].ptr, 3);
|
||||
assert(std.mem.eql(u8, a, []u8{ 4, 3, 2 }));
|
||||
}
|
||||
|
||||
fn incrementVoidPtrArray(array: ?*c_void, len: usize) void {
|
||||
var n: usize = 0;
|
||||
while (n < len) : (n += 1) {
|
||||
@ptrCast([*]u8, array.?)[n] += 1;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user