Skip to content
Open
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 Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ c2c: $(C2C)~

$(C2C)~: output/bootstrap/bootstrap $(C2C_DEPS)
@echo "---- running (bootstrapped$(C2FLAGS)) c2c ----"
@output/bootstrap/bootstrap c2c $(C2FLAGS) --fast --quiet --noplugins
@C2_PLUGINDIR=output/plugins C2_LIBDIR=libs output/bootstrap/bootstrap c2c $(C2FLAGS) --fast --quiet --noplugins
@rm -rf output/bootstrap/cgen
@mv -f output/c2c/* output/bootstrap
@echo "---- running c2c (no plugins$(C2FLAGS)) ----"
Expand Down
75 changes: 71 additions & 4 deletions common/file/file_utils.c2
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@
module file_utils;

import c_errno { * }
import stdlib { free }
import string { pstrcpy, strerror }
import stdlib { free, getenv }
import string { pstrcpy, strerror, strlen }
import sys_stat { * }
import unistd { getcwd }

public const u32 Max_path = 512;

Expand Down Expand Up @@ -56,7 +57,7 @@ fn usize copy_dirname(char* buf, usize size, const char* dir) {
// if the path fits in the destination array, a pointer to it is returned.
// otherwise the path is truncated, errno is set to ENAMETOOLONG and nil is returned
// both the filename and the extension can be nil or omitted
public fn const char* make_path(char* buf, usize size, const char* path, const char* filename = nil, const char* ext = nil) {
public fn char* make_path(char* buf, usize size, const char* path, const char* filename = nil, const char* ext = nil) {
usize pos = 0;
if (filename) {
if (*filename != '/') pos = copy_dirname(buf, size, path);
Expand All @@ -73,7 +74,7 @@ public fn const char* make_path(char* buf, usize size, const char* path, const c
// construct a path in a buffer from a directory name, a subdirectory name and a filename
// if the path fits in the destination array, a pointer to it is returned.
// otherwise the path is truncated, errno is set to ENAMETOOLONG and nil is returned
public fn const char* make_path3(char* buf, usize size, const char* dir, const char* subdir, const char* filename) {
public fn char* make_path3(char* buf, usize size, const char* dir, const char* subdir, const char* filename) {
usize pos = 0;
if (*filename != '/') {
if (*subdir != '/') pos = copy_dirname(buf, size, dir);
Expand All @@ -85,6 +86,72 @@ public fn const char* make_path3(char* buf, usize size, const char* dir, const c
return nil;
}

// construct an absolute path in a buffer from a pathname
// prepend home directory if pathname starts with '~/'
// prepend current directory unless pathname starts with '/'
// remove redundant '/./' and squeeze '/xxx/../' occurrences
public fn char* make_abs_path(char* buf, usize size, const char* path) {
usize pos = 0;
if (*path == '~' && (!path[1] || path[1] == '/')) {
char *homedir = getenv("HOME");
if (homedir) {
pos = pstrcpy(buf, size, homedir);
path++;
if (*path && pos && buf[pos - 1] == '/') path++;
pos = pstrcpy(buf + pos, size - pos, path);
}
} else
if (*path != '/') {
if (getcwd(buf, size)) {
pos = strlen(buf);
if (pos && buf[pos - 1] != '/') {
pos += pstrcpy(buf + pos, size - pos, "/");
}
pos += pstrcpy(buf + pos, size - pos, path);
}
}
if (!pos) {
pos = pstrcpy(buf, size, path);
}
char *p = buf;
char *q = buf;
for (;;) {
if (*p == '/' && p[1] == '.') {
if (!p[2] || p[2] == '/') {
// replace '/./' with '/'
p += 2;
continue;
}
if (p[2] == '.') {
// replace '/xxx/../' with '/'
if (!p[3] || p[3] == '/') {
while (q > buf && *--q != '/') continue;
p += 3;
continue;
}
}
}
if (!(*q++ = *p++)) break;
}
if (size > 1 && !*buf) {
buf[0] = '/';
buf[1] = '\0';
}
return buf;
}

public fn char* parent_dir(char* path) {
// truncate path to its parent directory
// return pointer past the trailing '/'
// return nil if no parent directory
char *tail = nil;
for (char *p = path; *p; p++) {
if (*p == '/' && p[1]) tail = p + 1;
}
if (tail) *tail = '\0';
return tail;
}

// returns 0 on success, errno on failure
// create a directory path, OK if exists already
public fn i32 create_path(const char* path) {
Expand Down
83 changes: 68 additions & 15 deletions compiler/main.c2
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import console;
import c2recipe { Recipe }
import compiler;
import constants { recipe_name }
import file_utils;
import file_utils { * }
#if C2_PLUGINS && !BOOTSTRAP
import git_version; // from plugin
#endif
Expand All @@ -39,7 +39,8 @@ import utils;
import c_errno { errno }
import stdio { snprintf }
import stdlib { exit, EXIT_FAILURE, EXIT_SUCCESS, getenv }
import string { memset, memchr, strlen, strerror, pstrcpy }
import string { memset, memchr, strlen, strerror, strdup, pstrcpy }
import unistd { getcwd }

type Options struct {
bool log_verbose;
Expand Down Expand Up @@ -76,7 +77,7 @@ fn void Options.free(Options* opts) {
}

fn void write_file_or_die(const char* filename, StringBuf* buf) {
file_utils.File file.init(filename);
File file.init(filename);
if (!file.write(buf.data(), buf.size())) {
console.error("c2c: cannot write to %s: %s", file.path, file.getError());
exit(EXIT_FAILURE);
Expand Down Expand Up @@ -108,7 +109,7 @@ end

fn void create_project(const char* name) {

if (file_utils.path_exists("main.c2") || file_utils.path_exists("recipe.txt")) {
if (path_exists("main.c2") || path_exists("recipe.txt")) {
console.error("c2c: main.c2 and/or recipe.txt already exist");
exit(EXIT_FAILURE);
}
Expand Down Expand Up @@ -496,7 +497,7 @@ type Context struct {

Recipe* recipe;
build_file.Info* build_info;
char[file_utils.Max_path] build_filename;
char[Max_path] build_filename;
i32 recipe_id;

PluginMgr* plugins;
Expand All @@ -518,6 +519,51 @@ fn void Context.init(Context* c, bool use_color) {
c.recipe_id = -1;
}

fn char* find_compiler_dir(char* buf, usize size) {
char[Max_path] path;
if (!getcwd(buf, size)) return nil;
for (;;) {
if (path_exists(make_path(path, countof(path), buf, "libs/libc/stdio.c2i"))) {
return buf;
}
if (!parent_dir(buf)) {
return nil;
}
}
}

fn char* get_plugin_dir(const char *progname) {
char[Max_path] path;
const char* plugin_dir = getenv("C2_PLUGINDIR");
if (!plugin_dir) {
// Should try and locate the compiler and check for development version or installed version
char[Max_path] comp_path;
if (find_compiler_dir(comp_path, countof(comp_path))) {
plugin_dir = make_path(path, countof(path), comp_path, "output/plugins");
} else
if (path_exists(make_abs_path(path, countof(path), "~/c2_plugins"))) {
plugin_dir = path;
}
}
return plugin_dir ? strdup(plugin_dir) : nil;
}

fn char* get_libdir(const char *progname) {
char[Max_path] path;
char *libdir = getenv("C2_LIBDIR");
if (!libdir) {
// Should try and locate the compiler and check for development version or installed version
char[Max_path] comp_path;
if (find_compiler_dir(comp_path, countof(comp_path))) {
libdir = make_path(path, countof(path), comp_path, "libs");
} else
if (path_exists(make_abs_path(path, countof(path), "~/c2_libs"))) {
libdir = path;
}
}
return libdir ? strdup(libdir) : nil;
}

fn void Context.handle_args(Context* c, i32 argc, char** argv) {
ArgumentParser ap.init(argc, argv, "c2c", Usage_help);
parse_arguments(&ap, &c.comp_opts, &c.opts);
Expand All @@ -527,6 +573,10 @@ fn void Context.handle_args(Context* c, i32 argc, char** argv) {
console.setQuiet(c.opts.quiet_mode);
console.setColor(c.opts.use_color);

// retrieve lib and plugin directories before changing current dir
char* plugin_dir = get_plugin_dir(argv[0]);
char* libdir = get_libdir(argv[0]);

const char[] notFound = "c2c: error: cannot find project root directory\n"
" c2c requires a %s file in the project root,\n"
" Use argument -h for c2c usage and a list of available options";
Expand All @@ -552,8 +602,8 @@ fn void Context.handle_args(Context* c, i32 argc, char** argv) {

if (c.opts.files.length()) {
// use basename of first filename as target name
const char* basename = file_utils.get_basename(c.opts.files.get(0));
const char* ext = file_utils.get_extension(basename);
const char* basename = get_basename(c.opts.files.get(0));
const char* ext = get_extension(basename);
u32 target_idx = c.auxPool.add(basename, (u32)(ext - basename), true);
BackEndKind backend = C;
if (c.opts.use_ir_backend) backend = IR;
Expand Down Expand Up @@ -622,16 +672,19 @@ fn void Context.handle_args(Context* c, i32 argc, char** argv) {
}
}
}

if (!have_plugin_dir) {
const char* plugin_dir = getenv("C2_PLUGINDIR");
if (plugin_dir) string_utils.split_paths(plugin_dir, c, on_plugin_dir);
else console.warn("environment variable C2_PLUGINDIR not set!");
if (plugin_dir) {
string_utils.split_paths(plugin_dir, c, on_plugin_dir);
} else {
console.warn("environment variable C2_PLUGINDIR not set!");
}
}

c.comp_opts.libdir = getenv("C2_LIBDIR");
if (!c.comp_opts.libdir && !c.opts.build_file) {
console.warn("environment variable C2_LIBDIR not set!");
if (libdir) {
c.comp_opts.libdir = libdir;
} else {
if (!c.opts.build_file) {
console.warn("environment variable C2_LIBDIR not set!");
}
}
}

Expand Down
9 changes: 5 additions & 4 deletions install_plugins.sh
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
#!/bin/sh

echo "---- installing c2c plugins in $C2_PLUGINDIR"

if [ $(uname -s) = 'Darwin' ] ; then
LIB_EXT='.dylib'
else
LIB_EXT='.so'
fi

if [ "$C2_PLUGINDIR" = "" ] ; then
echo C2_PLUGINDIR not set
exit 1
C2_PLUGINDIR=output/plugins
#echo C2_PLUGINDIR not set
#exit 1
fi

echo "---- installing c2c plugins in $C2_PLUGINDIR"

set -e
mkdir -p $C2_PLUGINDIR
cp output/deps_generator/libdeps_generator$LIB_EXT $C2_PLUGINDIR
Expand Down
5 changes: 4 additions & 1 deletion tools/tester/test_db.c2
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,10 @@ fn bool Db.parseKeyword(Db* db) {
StringBuf* build = StringBuf.create(1024, false, 0);
build.print("target: \"%s\"\n", db.target);
build.add("libdir:\n");
build.add(" - \"$C2_LIBDIR\"\n");
//build.add(" - \"$C2_LIBDIR\"\n");
char[file_utils.Max_path] libdir;
file_utils.make_abs_path(libdir, countof(libdir), "libs");
build.print(" - \"%s\"\n", libdir);
db.writeFile(buildfile_name, build.data(), build.size());
build.free();
db.skipLine();
Expand Down
Loading