authorgravatar for evan@lagerdata.comEvan Haas <evan@lagerdata.com> 2021-06-27 02:25:32-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-06-27 12:25:32+03:00
log3be682bac9b768ae6481ed2a07844ee8ba87a896
treecd78268604957493d47cf87df610ec5f18d433be
parent2ac769eab9b7dba4cd38e5de01dfa6400f7ebd5b
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

translate-c: Add documentation for `zig translate-c`


2 files changed, 172 insertions(+), 1 deletions(-)

doc/docgen.zig+13
......@@ -286,6 +286,7 @@ const Code = struct {
286286 link_libc: bool,
287287 link_mode: ?std.builtin.LinkMode,
288288 disable_cache: bool,
289 verbose_cimport: bool,
289290
290291 const Id = union(enum) {
291292 Test,
......@@ -536,6 +537,7 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
536537 var link_libc = false;
537538 var link_mode: ?std.builtin.LinkMode = null;
538539 var disable_cache = false;
540 var verbose_cimport = false;
539541
540542 const source_token = while (true) {
541543 const content_tok = try eatToken(tokenizer, Token.Id.Content);
......@@ -548,6 +550,8 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
548550 mode = .ReleaseSafe;
549551 } else if (mem.eql(u8, end_tag_name, "code_disable_cache")) {
550552 disable_cache = true;
553 } else if (mem.eql(u8, end_tag_name, "code_verbose_cimport")) {
554 verbose_cimport = true;
551555 } else if (mem.eql(u8, end_tag_name, "code_link_object")) {
552556 _ = try eatToken(tokenizer, Token.Id.Separator);
553557 const obj_tok = try eatToken(tokenizer, Token.Id.TagContent);
......@@ -591,6 +595,7 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
591595 .link_libc = link_libc,
592596 .link_mode = link_mode,
593597 .disable_cache = disable_cache,
598 .verbose_cimport = verbose_cimport,
594599 },
595600 });
596601 tokenizer.code_node_count += 1;
......@@ -1127,6 +1132,10 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
11271132 try out.print(" -target {s}", .{triple});
11281133 }
11291134 }
1135 if (code.verbose_cimport) {
1136 try build_args.append("--verbose-cimport");
1137 try out.print(" --verbose-cimport", .{});
1138 }
11301139 if (expected_outcome == .BuildFail) {
11311140 const result = try ChildProcess.exec(.{
11321141 .allocator = allocator,
......@@ -1213,6 +1222,10 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
12131222 const colored_stderr = try termColor(allocator, escaped_stderr);
12141223 const colored_stdout = try termColor(allocator, escaped_stdout);
12151224
1225 if (code.verbose_cimport) {
1226 const escaped_build_stderr = try escapeHtml(allocator, exec_result.stderr);
1227 try out.print("\n{s}", .{escaped_build_stderr});
1228 }
12161229 try out.print("\n$ ./{s}\n{s}{s}", .{ code.name, colored_stdout, colored_stderr });
12171230 if (exited_with_signal) {
12181231 try out.print("(process terminated by signal)", .{});
doc/langref.html.in+159-1
......@@ -9914,7 +9914,6 @@ lib.addCSourceFile("src/lib.c", &[_][]const u8{
99149914 </ul>
99159915 {#see_also|Primitive Types#}
99169916 {#header_close#}
9917
99189917 {#header_open|Import from C Header File#}
99199918 <p>
99209919 The {#syntax#}@cImport{#endsyntax#} builtin function can be used
......@@ -9954,6 +9953,165 @@ const c = @cImport({
99549953 {#see_also|@cImport|@cInclude|@cDefine|@cUndef|@import#}
99559954 {#header_close#}
99569955
9956 {#header_open|C Translation CLI#}
9957 Zig's C translation capability is available as a CLI tool via <code class="shell">zig translate-c</code>.
9958 It requires a single filename as an argument. It may also take a set of optional flags that are
9959 forwarded to clang. It writes the translated file to stdout.
9960 {#header_open|Command line flags#}
9961 <ul>
9962 <li>
9963 <code class="shell">-I</code>:
9964 Specify a search directory for include files. May be used multiple times. Equivalent to
9965 <a href="https://releases.llvm.org/12.0.0/tools/clang/docs/ClangCommandLineReference.html#cmdoption-clang-i-dir">
9966 clang's <code>-I</code> flag</a>. The current directory is <em>not</em> included by default;
9967 use <code>-I.</code> to include it.
9968 </li>
9969 <li>
9970 <code class="shell">-D</code>: Define a preprocessor macro. Equivalent to
9971 <a href="https://releases.llvm.org/12.0.0/tools/clang/docs/ClangCommandLineReference.html#cmdoption-clang-d-macro">
9972 clang's <code>-D</code> flag</a>.
9973 </li>
9974 <li>
9975 <code class="shell">-cflags [flags] --</code>: Pass arbitrary additional
9976 <a href="https://releases.llvm.org/12.0.0/tools/clang/docs/ClangCommandLineReference.html">command line
9977 flags</a> to clang. Note: the list of flags must end with <code>--</code>
9978 </li>
9979 <li>
9980 <code class="shell">-target</code>: The {#link|target triple|Targets#} for the translated Zig code.
9981 If no target is specified, the current host target will be used.
9982 </li>
9983 </ul>
9984 {#header_close#}
9985 {#header_open|Using -target and -cflags#}
9986 <p>
9987 <strong>Important!</strong> When translating C code with <code class="shell">zig translate-c</code>,
9988 you <strong>must</strong> use the same <code>-target</code> triple that you will use when compiling
9989 the translated code. In addition, you <strong>must</strong> ensure that the <code>-cflags</code> used,
9990 if any, match the cflags used by code on the target system. Using the incorrect <code>-target</code>
9991 or <code>-cflags</code> could result in clang or Zig parse failures, or subtle ABI incompatibilities
9992 when linking with C code.
9993 </p>
9994 <p class="file">varytarget.h</p>
9995 <pre><code class="c">long FOO = __LONG_MAX__;</code></pre>
9996 <pre><code class="shell">$ zig translate-c -target <strong>thumb-freestanding-gnueabihf</strong> varytarget.h|grep FOO
9997pub export var FOO: c_long = <strong>2147483647</strong>;</code></pre>
9998 <pre><code class="shell">$ zig translate-c -target <strong>x86_64-macos-gnu</strong> varytarget.h|grep FOO
9999pub export var FOO: c_long = <strong>9223372036854775807</strong>;</code></pre>
10000 <p class="file">varycflags.h</p>
10001 <pre><code class="c">enum FOO { BAR };
10002int do_something(enum FOO foo);</code></pre>
10003 <pre><code class="shell">$ zig translate-c varycflags.h|grep -B1 do_something
10004pub const enum_FOO = <strong>c_uint</strong>;
10005pub extern fn do_something(foo: enum_FOO) c_int;</code></pre>
10006 <pre><code class="shell">$ zig translate-c <strong>-cflags -fshort-enums --</strong> varycflags.h|grep -B1 do_something
10007pub const enum_FOO = <strong>u8</strong>;
10008pub extern fn do_something(foo: enum_FOO) c_int;</code></pre>
10009 {#header_close#}
10010 {#header_open|@cImport vs translate-c#}
10011 <p>{#syntax#}@cImport{#endsyntax#} and <code class="shell">zig translate-c</code> use the same underlying
10012 C translation functionality, so on a technical level they are equivalent. In practice,
10013 {#syntax#}@cImport{#endsyntax#} is useful as a way to quickly and easily access numeric constants, typedefs,
10014 and record types without needing any extra setup. If you need to pass {#link|cflags|Using -target and -cflags#}
10015 to clang, or if you would like to edit the translated code, it is recommended to use
10016 <code class="shell">zig translate-c</code> and save the results to a file. Common reasons for editing
10017 the generated code include: changing {#syntax#}anytype{#endsyntax#} parameters in function-like macros to more
10018 specific types; changing {#syntax#}[*c]T{#endsyntax#} pointers to {#syntax#}[*]T{#endsyntax#} or
10019 {#syntax#}*T{#endsyntax#} pointers for improved type safety; and
10020 {#link|enabling or disabling runtime safety|@setRuntimeSafety#} within specific functions.
10021 </p>
10022 {#header_close#}
10023 {#see_also|Targets|C Type Primitives|Pointers|C Pointers|Import from C Header File|@cInclude|@cImport|@setRuntimeSafety#}
10024 {#header_close#}
10025 {#header_open|C Translation Caching#}
10026 <p>
10027 The C translation feature (whether used via <code class="shell">zig translate-c</code> or
10028 {#syntax#}@cImport{#endsyntax#}) integrates with the Zig caching system. Subsequent runs with
10029 the same source file, target, and cflags will use the cache instead of repeatedly translating
10030 the same code.
10031 </p>
10032 <p>
10033 To see where the cached files are stored when compiling code that uses {#syntax#}@cImport{#endsyntax#},
10034 use the <code class="shell">--verbose-cimport</code> flag:
10035 </p>
10036 {#code_begin|exe|verbose#}
10037 {#link_libc#}
10038 {#code_verbose_cimport#}
10039const c = @cImport({
10040 @cDefine("_NO_CRT_STDIO_INLINE", "1");
10041 @cInclude("stdio.h");
10042});
10043pub fn main() void {
10044 _ = c;
10045}
10046 {#code_end#}
10047 <p>
10048 <code class="shell">cimport.h</code> contains the file to translate (constructed from calls to
10049 {#syntax#}@cInclude{#endsyntax#}, {#syntax#}@cDefine{#endsyntax#}, and {#syntax#}@cUndef{#endsyntax#}),
10050 <code class="shell">cimport.h.d</code> is the list of file dependencies, and
10051 <code class="shell">cimport.zig</code> contains the translated output.
10052 </p>
10053 {#see_also|Import from C Header File|C Translation CLI|@cInclude|@cImport#}
10054 {#header_close#}
10055 {#header_open|Translation failures#}
10056 <p>
10057 Some C constructs cannot be translated to Zig - for example, <em>goto</em>,
10058 structs with bitfields, and token-pasting macros. Zig employs <em>demotion</em> to allow translation
10059 to continue in the face of non-translateable entities.
10060 </p>
10061 <p>
10062 Demotion comes in three varieties - {#link|opaque#}, <em>extern</em>, and
10063 {#syntax#}@compileError{#endsyntax#}.
10064
10065 C structs and unions that cannot be translated correctly will be translated as {#syntax#}opaque{}{#endsyntax#}.
10066 Functions that contain opaque types or code constructs that cannot be translated will be demoted
10067 to {#syntax#}extern{#endsyntax#} declarations.
10068
10069 Thus, non-translateable types can still be used as pointers, and non-translateable functions
10070 can be called so long as the linker is aware of the compiled function.
10071 </p>
10072 <p>
10073 {#syntax#}@compileError{#endsyntax#} is used when top-level definitions (global variables,
10074 function prototypes, macros) cannot be translated or demoted. Since Zig uses lazy analysis for
10075 top-level declarations, untranslateable entities will not cause a compile error in your code unless
10076 you actually use them.
10077 </p>
10078 {#see_also|opaque|extern|@compileError#}
10079 {#header_close#}
10080 {#header_open|C Macros#}
10081 <p>
10082 C Translation makes a best-effort attempt to translate function-like macros into equivalent
10083 Zig functions. Since C macros operate at the level of lexical tokens, not all C macros
10084 can be translated to Zig. Macros that cannot be translated will be be demoted to
10085 {#syntax#}@compileError{#endsyntax#}. Note that C code which <em>uses</em> macros will be
10086 translated without any additional issues (since Zig operates on the pre-processed source
10087 with macros expanded). It is merely the macros themselves which may not be translateable to
10088 Zig.
10089 </p>
10090 <p>Consider the following example:</p>
10091 <p class="file">macro.c</p>
10092 <pre><code class="c">#define MAKELOCAL(NAME, INIT) int NAME = INIT
10093int foo(void) {
10094 MAKELOCAL(a, 1);
10095 MAKELOCAL(b, 2);
10096 return a + b;
10097}</code></pre>
10098<pre><code class="shell">$ zig translate-c macro.c > macro.zig
10099</code></pre>
10100 <p class="file">macro.zig</p>
10101 <pre>{#syntax#}pub export fn foo() c_int {
10102 var a: c_int = 1;
10103 var b: c_int = 2;
10104 return a + b;
10105}
10106pub const MAKELOCAL = @compileError("unable to translate C expr: unexpected token .Equal"); // macro.c:1:9{#endsyntax#}</pre>
10107 <p>Note that {#syntax#}foo{#endsyntax#} was translated correctly despite using a non-translateable
10108 macro. {#syntax#}MAKELOCAL{#endsyntax#} was demoted to {#syntax#}@compileError{#endsyntax#} since
10109 it cannot be expressed as a Zig function; this simply means that you cannot directly use
10110 {#syntax#}MAKELOCAL{#endsyntax#} from Zig.
10111 </p>
10112 {#see_also|@compileError#}
10113 {#header_close#}
10114
995710115 {#header_open|C Pointers#}
995810116 <p>
995910117 This type is to be avoided whenever possible. The only valid reason for using a C pointer is in