2015-08-06 07:22:21 +08:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2015 Andrew Kelley
|
|
|
|
*
|
|
|
|
* This file is part of zig, which is MIT licensed.
|
|
|
|
* See http://opensource.org/licenses/MIT
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
2015-08-06 11:26:58 +08:00
|
|
|
#include "buffer.hpp"
|
2015-11-24 13:47:25 +08:00
|
|
|
#include "codegen.hpp"
|
2015-12-01 10:58:53 +08:00
|
|
|
#include "os.hpp"
|
2015-12-03 15:47:35 +08:00
|
|
|
#include "error.hpp"
|
2015-08-06 11:26:58 +08:00
|
|
|
|
2015-08-06 07:22:21 +08:00
|
|
|
#include <stdio.h>
|
|
|
|
|
2015-11-05 15:05:25 +08:00
|
|
|
static int usage(const char *arg0) {
|
2015-12-04 06:59:14 +08:00
|
|
|
fprintf(stderr, "Usage: %s [command] [options]\n"
|
2015-11-05 15:05:25 +08:00
|
|
|
"Commands:\n"
|
2016-02-08 15:50:51 +08:00
|
|
|
" build create executable, object, or library from target\n"
|
|
|
|
" test create and run a test build\n"
|
|
|
|
" version print version number and exit\n"
|
|
|
|
" parseh convert a c header file to zig extern declarations\n"
|
2016-01-28 10:22:58 +08:00
|
|
|
"Options:\n"
|
2016-02-08 15:50:51 +08:00
|
|
|
" --release build with optimizations on and debug protection off\n"
|
|
|
|
" --static output will be statically linked\n"
|
|
|
|
" --strip exclude debug symbols\n"
|
|
|
|
" --export [exe|lib|obj] override output type\n"
|
|
|
|
" --name [name] override output name\n"
|
|
|
|
" --output [file] override destination path\n"
|
|
|
|
" --verbose turn on compiler debug output\n"
|
|
|
|
" --color [auto|off|on] enable or disable colored error messages\n"
|
|
|
|
" --libc-lib-dir [path] set the C compiler data path\n"
|
|
|
|
" --libc-static-lib-dir [path] set the C compiler data path\n"
|
|
|
|
" --libc-include-dir [path] set the C compiler data path\n"
|
2016-02-09 13:11:09 +08:00
|
|
|
" --dynamic-linker [path] set the path to ld.so\n"
|
2016-02-08 15:50:51 +08:00
|
|
|
" -isystem [dir] add additional search path for other .h files\n"
|
|
|
|
" -dirafter [dir] same as -isystem but do it last\n"
|
|
|
|
" --library-path [dir] add a directory to the library search path\n"
|
2015-08-06 07:22:21 +08:00
|
|
|
, arg0);
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
2016-01-31 16:20:47 +08:00
|
|
|
enum Cmd {
|
|
|
|
CmdInvalid,
|
|
|
|
CmdBuild,
|
2016-02-04 09:02:01 +08:00
|
|
|
CmdTest,
|
2016-01-31 16:20:47 +08:00
|
|
|
CmdVersion,
|
|
|
|
CmdParseH,
|
2015-12-01 10:58:53 +08:00
|
|
|
};
|
2015-08-06 07:22:21 +08:00
|
|
|
|
2016-01-31 16:20:47 +08:00
|
|
|
int main(int argc, char **argv) {
|
|
|
|
char *arg0 = argv[0];
|
|
|
|
Cmd cmd = CmdInvalid;
|
|
|
|
const char *in_file = nullptr;
|
|
|
|
const char *out_file = nullptr;
|
2016-02-04 09:02:01 +08:00
|
|
|
bool is_release_build = false;
|
2016-01-31 16:20:47 +08:00
|
|
|
bool strip = false;
|
|
|
|
bool is_static = false;
|
|
|
|
OutType out_type = OutTypeUnknown;
|
|
|
|
const char *out_name = nullptr;
|
|
|
|
bool verbose = false;
|
|
|
|
ErrColor color = ErrColorAuto;
|
2016-02-03 06:04:14 +08:00
|
|
|
const char *libc_lib_dir = nullptr;
|
2016-02-08 15:50:51 +08:00
|
|
|
const char *libc_static_lib_dir = nullptr;
|
2016-02-03 06:04:14 +08:00
|
|
|
const char *libc_include_dir = nullptr;
|
2016-02-09 13:11:09 +08:00
|
|
|
const char *dynamic_linker = nullptr;
|
2016-01-31 16:20:47 +08:00
|
|
|
ZigList<const char *> clang_argv = {0};
|
2016-02-01 09:32:07 +08:00
|
|
|
ZigList<const char *> lib_dirs = {0};
|
2015-12-03 15:47:35 +08:00
|
|
|
int err;
|
2015-12-01 10:58:53 +08:00
|
|
|
|
2016-01-31 16:20:47 +08:00
|
|
|
for (int i = 1; i < argc; i += 1) {
|
2015-11-05 15:05:25 +08:00
|
|
|
char *arg = argv[i];
|
2016-01-31 16:20:47 +08:00
|
|
|
|
2016-01-28 10:22:58 +08:00
|
|
|
if (arg[0] == '-') {
|
2015-11-28 12:24:11 +08:00
|
|
|
if (strcmp(arg, "--release") == 0) {
|
2016-02-04 09:02:01 +08:00
|
|
|
is_release_build = true;
|
2015-11-25 13:32:26 +08:00
|
|
|
} else if (strcmp(arg, "--strip") == 0) {
|
2016-01-31 16:20:47 +08:00
|
|
|
strip = true;
|
2015-11-25 13:32:26 +08:00
|
|
|
} else if (strcmp(arg, "--static") == 0) {
|
2016-01-31 16:20:47 +08:00
|
|
|
is_static = true;
|
2015-12-01 10:58:53 +08:00
|
|
|
} else if (strcmp(arg, "--verbose") == 0) {
|
2016-01-31 16:20:47 +08:00
|
|
|
verbose = true;
|
2015-11-05 15:05:25 +08:00
|
|
|
} else if (i + 1 >= argc) {
|
|
|
|
return usage(arg0);
|
|
|
|
} else {
|
|
|
|
i += 1;
|
2015-12-01 16:06:10 +08:00
|
|
|
if (i >= argc) {
|
|
|
|
return usage(arg0);
|
|
|
|
} else if (strcmp(arg, "--output") == 0) {
|
2016-01-31 16:20:47 +08:00
|
|
|
out_file = argv[i];
|
2015-11-28 12:24:11 +08:00
|
|
|
} else if (strcmp(arg, "--export") == 0) {
|
|
|
|
if (strcmp(argv[i], "exe") == 0) {
|
2016-01-31 16:20:47 +08:00
|
|
|
out_type = OutTypeExe;
|
2015-11-28 12:24:11 +08:00
|
|
|
} else if (strcmp(argv[i], "lib") == 0) {
|
2016-01-31 16:20:47 +08:00
|
|
|
out_type = OutTypeLib;
|
2015-11-28 12:24:11 +08:00
|
|
|
} else if (strcmp(argv[i], "obj") == 0) {
|
2016-01-31 16:20:47 +08:00
|
|
|
out_type = OutTypeObj;
|
2015-11-28 12:24:11 +08:00
|
|
|
} else {
|
|
|
|
return usage(arg0);
|
|
|
|
}
|
2015-12-01 16:06:10 +08:00
|
|
|
} else if (strcmp(arg, "--color") == 0) {
|
|
|
|
if (strcmp(argv[i], "auto") == 0) {
|
2016-01-31 16:20:47 +08:00
|
|
|
color = ErrColorAuto;
|
2015-12-01 16:06:10 +08:00
|
|
|
} else if (strcmp(argv[i], "on") == 0) {
|
2016-01-31 16:20:47 +08:00
|
|
|
color = ErrColorOn;
|
2015-12-01 16:06:10 +08:00
|
|
|
} else if (strcmp(argv[i], "off") == 0) {
|
2016-01-31 16:20:47 +08:00
|
|
|
color = ErrColorOff;
|
2015-12-01 16:06:10 +08:00
|
|
|
} else {
|
|
|
|
return usage(arg0);
|
|
|
|
}
|
2015-11-28 12:24:11 +08:00
|
|
|
} else if (strcmp(arg, "--name") == 0) {
|
2016-01-31 16:20:47 +08:00
|
|
|
out_name = argv[i];
|
2016-02-03 06:04:14 +08:00
|
|
|
} else if (strcmp(arg, "--libc-lib-dir") == 0) {
|
|
|
|
libc_lib_dir = argv[i];
|
2016-02-08 15:50:51 +08:00
|
|
|
} else if (strcmp(arg, "--libc-static-lib-dir") == 0) {
|
|
|
|
libc_static_lib_dir = argv[i];
|
2016-02-03 06:04:14 +08:00
|
|
|
} else if (strcmp(arg, "--libc-include-dir") == 0) {
|
|
|
|
libc_include_dir = argv[i];
|
2016-02-09 13:11:09 +08:00
|
|
|
} else if (strcmp(arg, "--dynamic-linker") == 0) {
|
|
|
|
dynamic_linker = argv[i];
|
2016-01-28 10:22:58 +08:00
|
|
|
} else if (strcmp(arg, "-isystem") == 0) {
|
2016-01-31 16:20:47 +08:00
|
|
|
clang_argv.append("-isystem");
|
|
|
|
clang_argv.append(argv[i]);
|
2016-01-28 10:22:58 +08:00
|
|
|
} else if (strcmp(arg, "-dirafter") == 0) {
|
2016-01-31 16:20:47 +08:00
|
|
|
clang_argv.append("-dirafter");
|
|
|
|
clang_argv.append(argv[i]);
|
2016-02-01 09:32:07 +08:00
|
|
|
} else if (strcmp(arg, "--library-path") == 0) {
|
|
|
|
lib_dirs.append(argv[i]);
|
2015-11-05 15:05:25 +08:00
|
|
|
} else {
|
|
|
|
return usage(arg0);
|
|
|
|
}
|
|
|
|
}
|
2016-01-31 16:20:47 +08:00
|
|
|
} else if (cmd == CmdInvalid) {
|
|
|
|
if (strcmp(arg, "build") == 0) {
|
|
|
|
cmd = CmdBuild;
|
|
|
|
} else if (strcmp(arg, "version") == 0) {
|
|
|
|
cmd = CmdVersion;
|
|
|
|
} else if (strcmp(arg, "parseh") == 0) {
|
|
|
|
cmd = CmdParseH;
|
2016-02-04 09:02:01 +08:00
|
|
|
} else if (strcmp(arg, "test") == 0) {
|
|
|
|
cmd = CmdTest;
|
2016-01-28 15:25:10 +08:00
|
|
|
} else {
|
2016-01-31 16:20:47 +08:00
|
|
|
fprintf(stderr, "Unrecognized command: %s\n", arg);
|
2016-01-19 12:28:54 +08:00
|
|
|
return usage(arg0);
|
|
|
|
}
|
|
|
|
} else {
|
2016-01-31 16:20:47 +08:00
|
|
|
switch (cmd) {
|
|
|
|
case CmdBuild:
|
|
|
|
case CmdParseH:
|
2016-02-04 09:02:01 +08:00
|
|
|
case CmdTest:
|
2016-01-31 16:20:47 +08:00
|
|
|
if (!in_file) {
|
|
|
|
in_file = arg;
|
|
|
|
} else {
|
|
|
|
return usage(arg0);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CmdVersion:
|
|
|
|
return usage(arg0);
|
|
|
|
case CmdInvalid:
|
|
|
|
zig_unreachable();
|
|
|
|
}
|
2016-01-28 07:30:52 +08:00
|
|
|
}
|
2016-01-27 15:01:49 +08:00
|
|
|
}
|
|
|
|
|
2016-01-31 16:20:47 +08:00
|
|
|
switch (cmd) {
|
|
|
|
case CmdBuild:
|
|
|
|
case CmdParseH:
|
2016-02-04 09:02:01 +08:00
|
|
|
case CmdTest:
|
2016-01-31 16:20:47 +08:00
|
|
|
{
|
|
|
|
if (!in_file)
|
|
|
|
return usage(arg0);
|
2016-01-27 15:01:49 +08:00
|
|
|
|
2016-01-31 16:20:47 +08:00
|
|
|
Buf in_file_buf = BUF_INIT;
|
|
|
|
buf_init_from_str(&in_file_buf, in_file);
|
|
|
|
|
|
|
|
Buf root_source_dir = BUF_INIT;
|
|
|
|
Buf root_source_code = BUF_INIT;
|
|
|
|
Buf root_source_name = BUF_INIT;
|
|
|
|
if (buf_eql_str(&in_file_buf, "-")) {
|
|
|
|
os_get_cwd(&root_source_dir);
|
|
|
|
if ((err = os_fetch_file(stdin, &root_source_code))) {
|
|
|
|
fprintf(stderr, "unable to read stdin: %s\n", err_str(err));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
buf_init_from_str(&root_source_name, "");
|
|
|
|
} else {
|
|
|
|
os_path_split(&in_file_buf, &root_source_dir, &root_source_name);
|
|
|
|
if ((err = os_fetch_file_path(buf_create_from_str(in_file), &root_source_code))) {
|
|
|
|
fprintf(stderr, "unable to open '%s': %s\n", in_file, err_str(err));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
2016-01-19 12:28:54 +08:00
|
|
|
|
2016-01-31 16:20:47 +08:00
|
|
|
CodeGen *g = codegen_create(&root_source_dir);
|
2016-02-04 09:02:01 +08:00
|
|
|
codegen_set_is_release(g, is_release_build);
|
|
|
|
codegen_set_is_test(g, cmd == CmdTest);
|
|
|
|
|
2016-01-31 16:20:47 +08:00
|
|
|
codegen_set_clang_argv(g, clang_argv.items, clang_argv.length);
|
|
|
|
codegen_set_strip(g, strip);
|
|
|
|
codegen_set_is_static(g, is_static);
|
2016-02-04 09:02:01 +08:00
|
|
|
if (out_type != OutTypeUnknown) {
|
2016-01-31 16:20:47 +08:00
|
|
|
codegen_set_out_type(g, out_type);
|
2016-02-04 09:02:01 +08:00
|
|
|
} else if (cmd == CmdTest) {
|
|
|
|
codegen_set_out_type(g, OutTypeExe);
|
|
|
|
}
|
|
|
|
if (out_name) {
|
2016-01-31 16:20:47 +08:00
|
|
|
codegen_set_out_name(g, buf_create_from_str(out_name));
|
2016-02-04 09:02:01 +08:00
|
|
|
} else if (cmd == CmdTest) {
|
|
|
|
codegen_set_out_name(g, buf_create_from_str("test"));
|
|
|
|
}
|
2016-02-03 06:04:14 +08:00
|
|
|
if (libc_lib_dir)
|
|
|
|
codegen_set_libc_lib_dir(g, buf_create_from_str(libc_lib_dir));
|
2016-02-08 15:50:51 +08:00
|
|
|
if (libc_static_lib_dir)
|
|
|
|
codegen_set_libc_static_lib_dir(g, buf_create_from_str(libc_static_lib_dir));
|
2016-02-03 06:04:14 +08:00
|
|
|
if (libc_include_dir)
|
|
|
|
codegen_set_libc_include_dir(g, buf_create_from_str(libc_include_dir));
|
2016-02-09 13:11:09 +08:00
|
|
|
if (dynamic_linker)
|
|
|
|
codegen_set_dynamic_linker(g, buf_create_from_str(dynamic_linker));
|
2016-01-31 16:20:47 +08:00
|
|
|
codegen_set_verbose(g, verbose);
|
|
|
|
codegen_set_errmsg_color(g, color);
|
|
|
|
|
2016-02-01 09:32:07 +08:00
|
|
|
for (int i = 0; i < lib_dirs.length; i += 1) {
|
|
|
|
codegen_add_lib_dir(g, lib_dirs.at(i));
|
|
|
|
}
|
|
|
|
|
2016-01-31 16:20:47 +08:00
|
|
|
if (cmd == CmdBuild) {
|
|
|
|
codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code);
|
|
|
|
codegen_link(g, out_file);
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
} else if (cmd == CmdParseH) {
|
|
|
|
codegen_parseh(g, &root_source_dir, &root_source_name, &root_source_code);
|
|
|
|
codegen_render_ast(g, stdout, 4);
|
|
|
|
return EXIT_SUCCESS;
|
2016-02-04 09:02:01 +08:00
|
|
|
} else if (cmd == CmdTest) {
|
|
|
|
codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code);
|
|
|
|
codegen_link(g, "./test");
|
|
|
|
ZigList<const char *> args = {0};
|
|
|
|
int return_code;
|
|
|
|
os_spawn_process("./test", args, &return_code);
|
|
|
|
if (return_code != 0) {
|
|
|
|
fprintf(stderr, "\nTests failed. Use the following command to reproduce the failure:\n");
|
|
|
|
fprintf(stderr, "./test\n");
|
|
|
|
}
|
|
|
|
return return_code;
|
2015-12-04 06:59:14 +08:00
|
|
|
} else {
|
2016-01-31 16:20:47 +08:00
|
|
|
zig_unreachable();
|
2015-12-04 06:59:14 +08:00
|
|
|
}
|
|
|
|
}
|
2016-01-31 16:20:47 +08:00
|
|
|
case CmdVersion:
|
|
|
|
printf("%s\n", ZIG_VERSION_STRING);
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
case CmdInvalid:
|
|
|
|
return usage(arg0);
|
2015-11-05 15:05:25 +08:00
|
|
|
}
|
|
|
|
}
|