commit b777ea65cd5dbcdc211bbccb2b5aed7b15658a0d
parent c5ce707a917dbe84bfdd3a8452479c2109e2f33e
Author: Joris Vink <joris@coders.se>
Date: Wed, 27 Jan 2016 21:32:57 +0100
Long day .. actually add the new build flavor code.
Diffstat:
4 files changed, 457 insertions(+), 139 deletions(-)
diff --git a/examples/json_yajl/README.md b/examples/json_yajl/README.md
@@ -3,14 +3,17 @@ This example demonstrates how you can use external libs in your application.
In this case we link against yajl (Yet Another JSON library) in order to
parse a JSON string that was POSTed to the server.
+Take a peek at conf/build.conf for different build flavors and how to
+link to other libraries.
+
Run:
```
- env LDFLAGS="-lyajl" kore run
+ $ kore run
```
Test:
```
- curl -i -k -d '{"foo":{"bar": "Hello world"}}' https://127.0.0.1:8888
+ $ curl -i -k -d '{"foo":{"bar": "Hello world"}}' https://127.0.0.1:8888
```
The result should echo back the foo.bar JSON path value: Hello world.
diff --git a/examples/json_yajl/src/json_yajl.c b/examples/json_yajl/src/json_yajl.c
@@ -89,7 +89,6 @@ page(struct http_request *req)
/* Release the JSON tree now. */
yajl_tree_free(node);
- kore_mem_free(body);
/* Respond to the client. */
http_response(req, 200, buf->data, buf->offset);
diff --git a/examples/tasks/README.md b/examples/tasks/README.md
@@ -6,16 +6,16 @@ before returning to the client.
Build:
```
- # env LDFLAGS="-I/path/to/libcurl -lcurl" kore build
+ $ kore build
```
Run:
```
- # kore run
+ $ kore run
```
Test:
```
- # curl -i -k https://127.0.0.1:8888/?user=astring
+ $ curl -i -k https://127.0.0.1:8888/?user=astring
The returned data must match what you supplied in user ([a-z] string)
```
diff --git a/src/cli.c b/src/cli.c
@@ -60,6 +60,15 @@
#define LD_FLAGS_MAX 30
#define CFLAGS_MAX 30
+struct buildopt {
+ char *name;
+ struct kore_buf *cflags;
+ struct kore_buf *ldflags;
+ TAILQ_ENTRY(buildopt) list;
+};
+
+TAILQ_HEAD(buildopt_list, buildopt);
+
struct cmd {
const char *name;
const char *descr;
@@ -73,7 +82,6 @@ struct filegen {
struct cfile {
struct stat st;
int build;
- int cpp;
char *name;
char *fpath;
char *opath;
@@ -83,16 +91,18 @@ struct cfile {
TAILQ_HEAD(cfile_list, cfile);
static void cli_fatal(const char *, ...) __attribute__((noreturn));
-
static void cli_file_close(int);
static void cli_run_kore(void *);
static void cli_generate_certs(void);
static void cli_link_library(void *);
static void cli_compile_cfile(void *);
+static char *cli_trim(char *, size_t);
static void cli_mkdir(const char *, int);
static int cli_dir_exists(const char *);
static int cli_file_exists(const char *);
static void cli_cleanup_files(const char *);
+static void cli_build_cflags(struct buildopt *);
+static void cli_build_ldflags(struct buildopt *);
static void cli_file_writef(int, const char *, ...);
static void cli_file_open(const char *, int, int *);
static void cli_file_remove(char *, struct dirent *);
@@ -107,13 +117,24 @@ static int cli_file_requires_build(struct stat *, const char *);
static void cli_find_files(const char *,
void (*cb)(char *, struct dirent *));
static void cli_add_cfile(char *, char *, char *,
- struct stat *, int, int);
+ struct stat *, int);
+
+static struct buildopt *cli_buildopt_new(const char *);
+static struct buildopt *cli_buildopt_find(const char *);
+static void cli_buildopt_cleanup(void);
+static void cli_buildopt_parse(const char *);
+static void cli_buildopt_cflags(struct buildopt *, const char *);
+static void cli_buildopt_ldflags(struct buildopt *, const char *);
+
+static void cli_flavor_load(void);
+static void cli_flavor_change(const char *);
static void cli_run(int, char **);
static void cli_help(int, char **);
static void cli_build(int, char **);
static void cli_clean(int, char **);
static void cli_create(int, char **);
+static void cli_flavor(int, char **);
static void file_create_src(void);
static void file_create_config(void);
@@ -125,6 +146,7 @@ static struct cmd cmds[] = {
{ "build", "build an application", cli_build },
{ "clean", "cleanup the build files", cli_clean },
{ "create", "create a new application skeleton", cli_create },
+ { "flavor", "switch build flavor", cli_flavor },
{ NULL, NULL, NULL }
};
@@ -159,7 +181,7 @@ static const char *src_data =
"}\n";
static const char *config_data =
- "# Placeholder configuration\n"
+ "# %s configuration\n"
"\n"
"bind\t\t127.0.0.1 8888\n"
"load\t\t./%s.so\n"
@@ -175,6 +197,26 @@ static const char *config_data =
"\tstatic\t/\tpage\n"
"}\n";
+static const char *build_data =
+ "# %s build config\n"
+ "# You can switch flavors using: kore flavor [newflavor]\n"
+ "\n"
+ "# The cflags below are shared between flavors\n"
+ "cflags=-Wall -Wmissing-declarations -Wshadow\n"
+ "cflags=-Wstrict-prototypes -Wmissing-prototypes\n"
+ "cflags=-Wpointer-arith -Wcast-qual -Wsign-compare\n"
+ "\n"
+ "dev {\n"
+ " # These cflags are added to the shared ones when\n"
+ " # you build the \"dev\" flavor.\n"
+ " cflags=-g\n"
+ "}\n"
+ "\n"
+ "#prod {\n"
+ "# You can specify additional CFLAGS here which are only\n"
+ "# included if you build with the \"prod\" flavor.\n"
+ "#}\n";
+
#if !defined(KORE_NO_TLS)
static const char *dh2048_data =
"-----BEGIN DH PARAMETERS-----\n"
@@ -187,15 +229,22 @@ static const char *dh2048_data =
"-----END DH PARAMETERS-----";
#endif
-static const char *gitignore_data = "*.o\n.objs\n%s.so\nassets.h\ncert\n";
+static const char *gitignore = "*.o\n.flavor\n.objs\n%s.so\nassets.h\ncert\n";
static int s_fd = -1;
+static int verbose = 0;
static char *appl = NULL;
static char *rootdir = NULL;
static char *compiler = "gcc";
static struct cfile_list source_files;
+static struct buildopt_list build_options;
static int cfiles_count;
static struct cmd *command = NULL;
+static int cflags_count = 0;
+static int ldflags_count = 0;
+static char *flavor = NULL;
+static char *cflags[CFLAGS_MAX];
+static char *ldflags[LD_FLAGS_MAX];
void
kore_cli_usage(int local)
@@ -229,6 +278,9 @@ kore_cli_main(int argc, char **argv)
(void)umask(S_IWGRP|S_IWOTH);
+ if ((flavor = strchr(argv[0], ':')) != NULL)
+ *(flavor)++ = '\0';
+
for (i = 0; cmds[i].name != NULL; i++) {
if (!strcmp(argv[0], cmds[i].name)) {
argc--;
@@ -285,40 +337,96 @@ cli_create(int argc, char **argv)
}
static void
-cli_build(int argc, char **argv)
+cli_flavor(int argc, char **argv)
{
- struct cfile *cf;
- struct timeval times[2];
- int requires_relink;
- char pwd[PATH_MAX], *src_path, *assets_header;
- char *assets_path, *p, *obj_path, *cpath, *config;
+ struct buildopt *bopt;
+ char pwd[MAXPATHLEN], *conf;
- if (argc == 0) {
- if (getcwd(pwd, sizeof(pwd)) == NULL)
- cli_fatal("could not get cwd: %s", errno_s);
+ if (getcwd(pwd, sizeof(pwd)) == NULL)
+ cli_fatal("could not get cwd: %s", errno_s);
- rootdir = ".";
- appl = basename(pwd);
+ appl = basename(pwd);
+ (void)cli_vasprintf(&conf, "conf/%s.conf", appl);
+ if (!cli_dir_exists("conf") || !cli_file_exists(conf))
+ cli_fatal("%s doesn't appear to be a kore app", appl);
+ free(conf);
+
+ TAILQ_INIT(&build_options);
+ (void)cli_buildopt_new("_default");
+ cli_buildopt_parse("conf/build.conf");
+
+ if (argc == 0) {
+ cli_flavor_load();
+ TAILQ_FOREACH(bopt, &build_options, list) {
+ if (!strcmp(bopt->name, "_default"))
+ continue;
+ if (!strcmp(bopt->name, flavor)) {
+ printf("* %s\n", bopt->name);
+ } else {
+ printf(" %s\n", bopt->name);
+ }
+ }
} else {
- appl = argv[0];
- rootdir = appl;
+ cli_flavor_change(argv[0]);
+ printf("changed build flavor to: %s\n", argv[0]);
}
+ cli_buildopt_cleanup();
+}
+
+static void
+cli_build(int argc, char **argv)
+{
+ struct cfile *cf;
+ struct buildopt *bopt;
+ struct timeval times[2];
+ char *build_path;
+ int requires_relink, l;
+ char *sofile, *config, *data;
+ char *assets_path, *p, *obj_path, *cpath;
+ char pwd[PATH_MAX], *src_path, *assets_header;
+
+ if (argc == 1 && !strcmp(argv[0], "-v"))
+ verbose = 1;
+
+ if (getcwd(pwd, sizeof(pwd)) == NULL)
+ cli_fatal("could not get cwd: %s", errno_s);
+
+ rootdir = ".";
+ appl = basename(pwd);
+
if ((p = getenv("CC")) != NULL)
compiler = p;
cfiles_count = 0;
TAILQ_INIT(&source_files);
+ TAILQ_INIT(&build_options);
(void)cli_vasprintf(&src_path, "%s/src", rootdir);
(void)cli_vasprintf(&assets_path, "%s/assets", rootdir);
(void)cli_vasprintf(&config, "%s/conf/%s.conf", rootdir, appl);
(void)cli_vasprintf(&assets_header, "%s/src/assets.h", rootdir);
+ (void)cli_vasprintf(&build_path, "%s/conf/build.conf", rootdir);
+
if (!cli_dir_exists(src_path) || !cli_file_exists(config))
cli_fatal("%s doesn't appear to be a kore app", appl);
-
free(config);
+ cli_flavor_load();
+ bopt = cli_buildopt_new("_default");
+ if (!cli_file_exists(build_path)) {
+ l = cli_vasprintf(&data, build_data, appl);
+ cli_file_create("conf/build.conf", data, l);
+ free(data);
+ }
+
+ cli_buildopt_parse(build_path);
+ free(build_path);
+
+ printf("building %s (%s)\n", appl, flavor);
+ cli_build_cflags(bopt);
+ cli_build_ldflags(bopt);
+
(void)cli_vasprintf(&obj_path, "%s/.objs", rootdir);
if (!cli_dir_exists(obj_path))
cli_mkdir(obj_path, 0755);
@@ -342,10 +450,9 @@ cli_build(int argc, char **argv)
/* Build all source files. */
cli_find_files(src_path, cli_register_cfile);
-
free(src_path);
- requires_relink = 0;
+ requires_relink = 0;
TAILQ_FOREACH(cf, &source_files, list) {
if (cf->build == 0)
continue;
@@ -373,12 +480,18 @@ cli_build(int argc, char **argv)
}
free(cpath);
+ (void)cli_vasprintf(&sofile, "%s.so", appl);
+ if (!cli_file_exists(sofile))
+ requires_relink++;
+ free(sofile);
+
if (requires_relink) {
cli_spawn_proc(cli_link_library, NULL);
printf("%s built successfully!\n", appl);
} else {
- printf("nothing to be done\n");
+ printf("nothing to be done!\n");
}
+ cli_buildopt_cleanup();
}
static void
@@ -432,11 +545,14 @@ file_create_config(void)
char *name, *data;
(void)cli_vasprintf(&name, "conf/%s.conf", appl);
- l = cli_vasprintf(&data, config_data, appl);
+ l = cli_vasprintf(&data, config_data, appl, appl);
cli_file_create(name, data, l);
-
free(name);
free(data);
+
+ l = cli_vasprintf(&data, build_data, appl);
+ cli_file_create("conf/build.conf", data, l);
+ free(data);
}
static void
@@ -445,7 +561,7 @@ file_create_gitignore(void)
int l;
char *data;
- l = cli_vasprintf(&data, gitignore_data, appl);
+ l = cli_vasprintf(&data, gitignore, appl);
cli_file_create(".gitignore", data, l);
free(data);
}
@@ -617,7 +733,7 @@ cli_build_asset(char *fpath, struct dirent *dp)
cli_write_asset(name, ext);
*ext = '_';
- cli_add_cfile(name, cpath, opath, &st, 0, 0);
+ cli_add_cfile(name, cpath, opath, &st, 0);
kore_mem_free(name);
return;
}
@@ -676,13 +792,13 @@ cli_build_asset(char *fpath, struct dirent *dp)
*--ext = '.';
/* Register the .c file now (cpath is free'd later). */
- cli_add_cfile(name, cpath, opath, &st, 1, 0);
+ cli_add_cfile(name, cpath, opath, &st, 1);
kore_mem_free(name);
}
static void
cli_add_cfile(char *name, char *fpath, char *opath, struct stat *st,
- int build, int cpp)
+ int build)
{
struct cfile *cf;
@@ -691,7 +807,6 @@ cli_add_cfile(char *name, char *fpath, char *opath, struct stat *st,
cf->st = *st;
cf->build = build;
- cf->cpp = cpp;
cf->fpath = fpath;
cf->opath = opath;
cf->name = kore_strdup(name);
@@ -704,27 +819,21 @@ cli_register_cfile(char *fpath, struct dirent *dp)
{
struct stat st;
char *ext, *opath;
- int cpp;
if ((ext = strrchr(fpath, '.')) == NULL ||
(strcmp(ext, ".c") && strcmp(ext, ".cpp")))
return;
- if (!strcmp(ext, ".cpp"))
- cpp = 1;
- else
- cpp = 0;
-
if (stat(fpath, &st) == -1)
cli_fatal("stat(%s): %s", fpath, errno_s);
(void)cli_vasprintf(&opath, "%s/.objs/%s.o", rootdir, dp->d_name);
if (!cli_file_requires_build(&st, opath)) {
- cli_add_cfile(dp->d_name, fpath, opath, &st, 0, cpp);
+ cli_add_cfile(dp->d_name, fpath, opath, &st, 0);
return;
}
- cli_add_cfile(dp->d_name, fpath, opath, &st, 1, cpp);
+ cli_add_cfile(dp->d_name, fpath, opath, &st, 1);
}
static void
@@ -876,75 +985,15 @@ cli_generate_certs(void)
static void
cli_compile_cfile(void *arg)
{
- int idx, f, i;
+ int idx, i;
struct cfile *cf = arg;
- char *flags[CFLAGS_MAX], *p;
- char *args[32 + CFLAGS_MAX], *ipath[2], *cppstandard;
-#if defined(KORE_USE_PGSQL)
- char *ppath;
-#endif
-
- (void)cli_vasprintf(&ipath[0], "-I%s/src", rootdir);
- (void)cli_vasprintf(&ipath[1], "-I%s/src/includes", rootdir);
+ char *args[32 + CFLAGS_MAX];
idx = 0;
args[idx++] = compiler;
- args[idx++] = ipath[0];
- args[idx++] = ipath[1];
-#if defined(PREFIX)
- (void)cli_vasprintf(&args[idx++], "-I%s/include", PREFIX);
-#else
- args[idx++] = "-I/usr/local/include";
-#endif
-
-#if defined(__MACH__)
- /* Add default openssl include path from homebrew / ports under OSX. */
- args[idx++] = "-I/opt/local/include";
- args[idx++] = "-I/usr/local/opt/openssl/include";
-#endif
-
- /* Add any user specified flags. */
- if ((p = getenv("CFLAGS")) != NULL)
- f = kore_split_string(p, " ", flags, CFLAGS_MAX);
- else
- f = 0;
- for (i = 0; i < f; i++)
- args[idx++] = flags[i];
-
-#if defined(KORE_USE_PGSQL)
- (void)cli_vasprintf(&ppath, "-I%s", PGSQL_INCLUDE_PATH);
- args[idx++] = ppath;
-#endif
-
-#if defined(KORE_NO_HTTP)
- args[idx++] = "-DKORE_NO_HTTP";
-#endif
-#if defined(KORE_NO_TLS)
- args[idx++] = "-DKORE_NO_TLS";
-#endif
- args[idx++] = "-Wall";
- args[idx++] = "-Wmissing-declarations";
- args[idx++] = "-Wshadow";
- args[idx++] = "-Wpointer-arith";
- args[idx++] = "-Wcast-qual";
- args[idx++] = "-Wsign-compare";
- args[idx++] = "-fPIC";
- args[idx++] = "-g";
-
- if (cf->cpp) {
- args[idx++] = "-Woverloaded-virtual";
- args[idx++] = "-Wold-style-cast";
- args[idx++] = "-Wnon-virtual-dtor";
-
- if ((p = getenv("CXXSTD")) != NULL) {
- (void)cli_vasprintf(&cppstandard, "-std=%s", p);
- args[idx++] = cppstandard;
- }
- } else {
- args[idx++] = "-Wstrict-prototypes";
- args[idx++] = "-Wmissing-prototypes";
- }
+ for (i = 0; i < cflags_count; i++)
+ args[idx++] = cflags[i];
args[idx++] = "-c";
args[idx++] = cf->fpath;
@@ -959,47 +1008,20 @@ static void
cli_link_library(void *arg)
{
struct cfile *cf;
- int idx, f, i, has_cpp;
+ int idx, i;
+ char *libname;
char *args[cfiles_count + 11 + LD_FLAGS_MAX];
- char *p, *libname, *flags[LD_FLAGS_MAX], *cpplib;
-
- if ((p = getenv("LDFLAGS")) != NULL)
- f = kore_split_string(p, " ", flags, LD_FLAGS_MAX);
- else
- f = 0;
(void)cli_vasprintf(&libname, "%s/%s.so", rootdir, appl);
idx = 0;
args[idx++] = compiler;
-#if defined(__MACH__)
- args[idx++] = "-dynamiclib";
- args[idx++] = "-undefined";
- args[idx++] = "suppress";
- args[idx++] = "-flat_namespace";
-#else
- args[idx++] = "-shared";
-#endif
-
- has_cpp = 0;
- TAILQ_FOREACH(cf, &source_files, list) {
- if (cf->cpp)
- has_cpp = 1;
+ TAILQ_FOREACH(cf, &source_files, list)
args[idx++] = cf->opath;
- }
- if (has_cpp) {
- if ((p = getenv("CXXLIB")) != NULL) {
- (void)cli_vasprintf(&cpplib, "-l%s", p);
- args[idx++] = cpplib;
- } else {
- args[idx++] = "-lstdc++";
- }
- }
-
- for (i = 0; i < f; i++)
- args[idx++] = flags[i];
+ for (i = 0; i < ldflags_count; i++)
+ args[idx++] = ldflags[i];
args[idx++] = "-o";
args[idx++] = libname;
@@ -1024,6 +1046,285 @@ cli_run_kore(void *arg)
}
static void
+cli_buildopt_parse(const char *path)
+{
+ FILE *fp;
+ struct buildopt *bopt;
+ char buf[BUFSIZ], *p, *t, *s;
+
+ if ((fp = fopen(path, "r")) == NULL)
+ cli_fatal("cli_buildopt_parse: fopen(%s): %s", path, errno_s);
+
+ bopt = NULL;
+
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ p = buf;
+ buf[strcspn(buf, "\n")] = '\0';
+
+ while (isspace(*p))
+ p++;
+ if (p[0] == '#' || p[0] == '\0')
+ continue;
+
+ for (t = p; *t != '\0'; t++) {
+ if (*t == '\t')
+ *t = ' ';
+ }
+
+ if (bopt != NULL && !strcmp(p, "}")) {
+ bopt = NULL;
+ continue;
+ }
+
+ if (bopt == NULL) {
+ if ((t = strchr(p, '=')) != NULL)
+ goto parse_option;
+ if ((t = strchr(p, ' ')) == NULL)
+ cli_fatal("unexpected '%s'", p);
+ *(t)++ = '\0';
+ if (strcmp(t, "{"))
+ cli_fatal("expected '{', got '%s'", t);
+ bopt = cli_buildopt_new(p);
+ continue;
+ }
+
+ if ((t = strchr(p, '=')) == NULL) {
+ printf("bad buildopt line: '%s'\n", p);
+ continue;
+ }
+
+parse_option:
+ *(t)++ = '\0';
+
+ cli_trim(p, strlen(p));
+ cli_trim(t, strlen(t));
+
+ while (isspace(*p))
+ p++;
+ s = p + strlen(p) - 1;
+ while (isspace(*s))
+ *(s)-- = '\0';
+
+ while (isspace(*t))
+ t++;
+ s = t + strlen(t) - 1;
+ while (isspace(*s))
+ *(s)-- = '\0';
+
+ if (!strcasecmp(p, "cflags")) {
+ cli_buildopt_cflags(bopt, t);
+ } else if (!strcasecmp(p, "ldflags")) {
+ cli_buildopt_ldflags(bopt, t);
+ } else {
+ printf("ignoring unknown option %s\n", p);
+ }
+ }
+}
+
+static struct buildopt *
+cli_buildopt_new(const char *name)
+{
+ struct buildopt *bopt;
+
+ bopt = kore_malloc(sizeof(*bopt));
+ bopt->cflags = NULL;
+ bopt->ldflags = NULL;
+ bopt->name = kore_strdup(name);
+
+ TAILQ_INSERT_TAIL(&build_options, bopt, list);
+ return (bopt);
+}
+
+static struct buildopt *
+cli_buildopt_find(const char *name)
+{
+ struct buildopt *bopt;
+
+ TAILQ_FOREACH(bopt, &build_options, list) {
+ if (!strcmp(bopt->name, name))
+ return (bopt);
+ }
+
+ return (NULL);
+}
+
+static void
+cli_buildopt_cleanup(void)
+{
+ struct buildopt *bopt, *next;
+
+ for (bopt = TAILQ_FIRST(&build_options); bopt != NULL; bopt = next) {
+ next = TAILQ_NEXT(bopt, list);
+ TAILQ_REMOVE(&build_options, bopt, list);
+
+ if (bopt->cflags != NULL)
+ kore_buf_free(bopt->cflags);
+ if (bopt->ldflags != NULL)
+ kore_buf_free(bopt->ldflags);
+ kore_mem_free(bopt);
+ }
+}
+
+static void
+cli_buildopt_cflags(struct buildopt *bopt, const char *string)
+{
+ if (bopt == NULL) {
+ if ((bopt = cli_buildopt_find("_default")) == NULL)
+ cli_fatal("no _default build options");
+ }
+
+ if (bopt->cflags == NULL)
+ bopt->cflags = kore_buf_create(128);
+
+ kore_buf_appendf(bopt->cflags, "%s ", string);
+}
+
+static void
+cli_buildopt_ldflags(struct buildopt *bopt, const char *string)
+{
+ if (bopt == NULL) {
+ if ((bopt = cli_buildopt_find("_default")) == NULL)
+ cli_fatal("no _default build options");
+ }
+
+ if (bopt->ldflags == NULL)
+ bopt->ldflags = kore_buf_create(128);
+
+ kore_buf_appendf(bopt->ldflags, "%s ", string);
+}
+
+static void
+cli_build_cflags(struct buildopt *bopt)
+{
+ struct buildopt *obopt;
+ char *string;
+
+ if ((obopt = cli_buildopt_find(flavor)) == NULL)
+ cli_fatal("no such build flavor: %s", flavor);
+
+ if (bopt->cflags == NULL)
+ bopt->cflags = kore_buf_create(128);
+
+ kore_buf_appendf(bopt->cflags,
+ "-fPIC -I%s/src -I%s/src/includes ", rootdir, rootdir);
+#if defined(PREFIX)
+ kore_buf_appendf(bopt->cflags, "-I%s/include ", PREFIX);
+#else
+ kore_buf_appendf(bopt->cflags, "-I/usr/local/include ");
+#endif
+#if defined(__MACH__)
+ /* Add default openssl include path from homebrew / ports under OSX. */
+ kore_buf_appendf(bopt->cflags, "-I/opt/local/include ");
+ kore_buf_appendf(bopt->cflags, "-I/usr/local/opt/openssl/include ");
+#endif
+#if defined(KORE_USE_PGSQL)
+ kore_buf_appendf(bopt->cflags, "-I%s ", PGSQL_INCLUDE_PATH);
+#endif
+#if defined(KORE_NO_HTTP)
+ kore_buf_appendf(bopt->cflags, "-DKORE_NO_HTTP ");
+#endif
+#if defined(KORE_NO_TLS)
+ kore_buf_appendf(bopt->cflags, "-DKORE_NO_TLS ");
+#endif
+
+ if (obopt != NULL && obopt->cflags != NULL) {
+ kore_buf_append(bopt->cflags, obopt->cflags->data,
+ obopt->cflags->offset);
+ }
+
+ string = kore_buf_stringify(bopt->cflags);
+ if (verbose)
+ printf("CFLAGS=%s\n", string);
+ cflags_count = kore_split_string(string, " ", cflags, CFLAGS_MAX);
+}
+
+static void
+cli_build_ldflags(struct buildopt *bopt)
+{
+ struct buildopt *obopt;
+ char *string;
+
+ if ((obopt = cli_buildopt_find(flavor)) == NULL)
+ cli_fatal("no such build flavor: %s", flavor);
+
+ if (bopt->ldflags == NULL)
+ bopt->ldflags = kore_buf_create(128);
+
+#if defined(__MACH__)
+ kore_buf_appendf(bopt->ldflags,
+ "-dynamiclib -undefined suppress -flat_namespace ");
+#else
+ kore_buf_appendf(bopt->ldflags, "-shared ");
+#endif
+
+ if (obopt != NULL && obopt->ldflags != NULL) {
+ kore_buf_append(bopt->ldflags, obopt->ldflags->data,
+ obopt->ldflags->offset);
+ }
+
+ string = kore_buf_stringify(bopt->ldflags);
+ if (verbose)
+ printf("LDFLAGS=%s\n", string);
+ ldflags_count = kore_split_string(string, " ", ldflags, LD_FLAGS_MAX);
+}
+
+static void
+cli_flavor_load(void)
+{
+ FILE *fp;
+ char buf[BUFSIZ], pwd[MAXPATHLEN], *p, *conf;
+
+ if (getcwd(pwd, sizeof(pwd)) == NULL)
+ cli_fatal("could not get cwd: %s", errno_s);
+
+ appl = basename(pwd);
+ (void)cli_vasprintf(&conf, "conf/%s.conf", appl);
+
+ if (!cli_dir_exists("conf") || !cli_file_exists(conf))
+ cli_fatal("%s doesn't appear to be a kore app", appl);
+ free(conf);
+
+ if ((fp = fopen(".flavor", "r")) == NULL) {
+ flavor = kore_strdup("dev");
+ return;
+ }
+
+ if (fgets(buf, sizeof(buf), fp) == NULL)
+ cli_fatal("failed to read flavor from file");
+
+ if ((p = strchr(buf, '\n')) != NULL)
+ *p = '\0';
+
+ flavor = kore_strdup(buf);
+ (void)fclose(fp);
+}
+
+static void
+cli_flavor_change(const char *name)
+{
+ FILE *fp;
+ int ret;
+ struct buildopt *bopt;
+
+ if ((bopt = cli_buildopt_find(name)) == NULL)
+ cli_fatal("no such flavor: %s", name);
+
+ if ((fp = fopen(".flavor.tmp", "w")) == NULL)
+ cli_fatal("failed to open temporary file to save flavor");
+
+ ret = fprintf(fp, "%s\n", name);
+ if (ret == -1 || (size_t)ret != (strlen(name) + 1))
+ cli_fatal("failed to write new build flavor");
+
+ (void)fclose(fp);
+
+ if (rename(".flavor.tmp", ".flavor") == -1)
+ cli_fatal("failed to replace build flavor");
+
+ cli_clean(0, NULL);
+}
+
+static void
cli_spawn_proc(void (*cb)(void *), void *arg)
{
pid_t pid;
@@ -1074,6 +1375,21 @@ cli_cleanup_files(const char *spath)
printf("couldn't rmdir %s\n", spath);
}
+static char *
+cli_trim(char *string, size_t len)
+{
+ char *end;
+
+ end = string + strlen(string) - 1;
+ while (isspace(*string))
+ string++;
+
+ while (isspace(*end) && end > string)
+ *(end)-- = '\0';
+
+ return (string);
+}
+
static void
cli_fatal(const char *fmt, ...)
{