commit ec7a7b33e7bde24e9af252602f29ed309656d74e
parent 8d92dd2af4c436b44cda972cca409157f24e2928
Author: Joris Vink <joris@coders.se>
Date:   Wed, 29 Jun 2016 16:23:00 +0200
Merge pull request #132 from nibroc/cpp
Compile and link C++ with g++ instead of gcc
Diffstat:
2 files changed, 153 insertions(+), 49 deletions(-)
diff --git a/examples/cpp/conf/build.conf b/examples/cpp/conf/build.conf
@@ -6,10 +6,14 @@ cflags=-Wall -Wmissing-declarations -Wshadow
 cflags=-Wstrict-prototypes -Wmissing-prototypes
 cflags=-Wpointer-arith -Wcast-qual -Wsign-compare
 
+cxxflags=-Wall -Wmissing-declarations -Wshadow
+cxxflags=-Wpointer-arith -Wcast-qual -Wsign-compare
+
 dev {
 	# These cflags are added to the shared ones when
 	# you build the "dev" flavor.
 	cflags=-g
+	cxxflags=-g
 }
 
 #prod {
diff --git a/src/cli.c b/src/cli.c
@@ -60,10 +60,16 @@
 
 #define LD_FLAGS_MAX		30
 #define CFLAGS_MAX		30
+#define CXXFLAGS_MAX		30
+
+#define BUILD_NOBUILD		0
+#define BUILD_C		1
+#define BUILD_CXX		2
 
 struct buildopt {
 	char			*name;
 	struct kore_buf		*cflags;
+	struct kore_buf		*cxxflags;
 	struct kore_buf		*ldflags;
 	TAILQ_ENTRY(buildopt)	list;
 };
@@ -96,12 +102,13 @@ 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 void		cli_compile_source_file(void *);
 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_cxxflags(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 *);
@@ -111,12 +118,12 @@ static void		cli_file_write(int, const void *, size_t);
 static int		cli_vasprintf(char **, const char *, ...);
 static void		cli_spawn_proc(void (*cb)(void *), void *);
 static void		cli_write_asset(const char *, const char *);
-static void		cli_register_cfile(char *, struct dirent *);
+static void		cli_register_source_file(char *, struct dirent *);
 static void		cli_file_create(const char *, const char *, size_t);
 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 *,
+static void		cli_add_source_file(char *, char *, char *,
 			    struct stat *, int);
 
 static struct buildopt	*cli_buildopt_new(const char *);
@@ -124,6 +131,7 @@ 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_cxxflags(struct buildopt *, const char *);
 static void		cli_buildopt_ldflags(struct buildopt *, const char *);
 
 static void		cli_flavor_load(void);
@@ -201,19 +209,23 @@ 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"
+	"# The flags 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"
+	"cxxflags=-Wall -Wmissing-declarations -Wshadow\n"
+	"cxxflags=-Wpointer-arith -Wcast-qual -Wsign-compare\n"
+	"\n"
 	"dev {\n"
-	"	# These cflags are added to the shared ones when\n"
+	"	# These flags are added to the shared ones when\n"
 	"	# you build the \"dev\" flavor.\n"
 	"	cflags=-g\n"
+	"	cxxflags=-g\n"
 	"}\n"
 	"\n"
 	"#prod {\n"
-	"#	You can specify additional CFLAGS here which are only\n"
+	"#	You can specify additional flags here which are only\n"
 	"#	included if you build with the \"prod\" flavor.\n"
 	"#}\n";
 
@@ -234,15 +246,20 @@ static const char *gitignore = "*.o\n.flavor\n.objs\n%s.so\nassets.h\ncert\n";
 static int			s_fd = -1;
 static char			*appl = NULL;
 static char			*rootdir = NULL;
-static char			*compiler = "gcc";
+static char			*compiler_c = "gcc";
+static char			*compiler_cpp = "g++";
+static char			*compiler_ld = "gcc";
 static struct cfile_list	source_files;
 static struct buildopt_list	build_options;
-static int			cfiles_count;
+static int			source_files_count;
+static int			cxx_files_count;
 static struct cmd		*command = NULL;
 static int			cflags_count = 0;
+static int			cxxflags_count = 0;
 static int			ldflags_count = 0;
 static char			*flavor = NULL;
 static char			*cflags[CFLAGS_MAX];
+static char			*cxxflags[CXXFLAGS_MAX];
 static char			*ldflags[LD_FLAGS_MAX];
 
 void
@@ -392,9 +409,13 @@ cli_build(int argc, char **argv)
 	appl = basename(pwd);
 
 	if ((p = getenv("CC")) != NULL)
-		compiler = p;
+		compiler_c = p;
+
+	if ((p = getenv("CXX")) != NULL)
+		compiler_cpp = p;
 
-	cfiles_count = 0;
+	source_files_count = 0;
+	cxx_files_count = 0;
 	TAILQ_INIT(&source_files);
 	TAILQ_INIT(&build_options);
 
@@ -419,8 +440,13 @@ cli_build(int argc, char **argv)
 	cli_buildopt_parse(build_path);
 	free(build_path);
 
+	/* Build all source files. */
+	cli_find_files(src_path, cli_register_source_file);
+	free(src_path);
+
 	printf("building %s (%s)\n", appl, flavor);
 	cli_build_cflags(bopt);
+	cli_build_cxxflags(bopt);
 	cli_build_ldflags(bopt);
 
 	(void)cli_vasprintf(&obj_path, "%s/.objs", rootdir);
@@ -444,17 +470,13 @@ cli_build(int argc, char **argv)
 
 	free(assets_path);
 
-	/* Build all source files. */
-	cli_find_files(src_path, cli_register_cfile);
-	free(src_path);
-
 	requires_relink = 0;
 	TAILQ_FOREACH(cf, &source_files, list) {
-		if (cf->build == 0)
+		if (cf->build == BUILD_NOBUILD)
 			continue;
 
 		printf("compiling %s\n", cf->name);
-		cli_spawn_proc(cli_compile_cfile, cf);
+		cli_spawn_proc(cli_compile_source_file, cf);
 
 		times[0].tv_usec = 0;
 		times[0].tv_sec = cf->st.st_mtime;
@@ -463,6 +485,10 @@ cli_build(int argc, char **argv)
 		if (utimes(cf->opath, times) == -1)
 			printf("utime(%s): %s\n", cf->opath, errno_s);
 
+		if (cf->build == BUILD_CXX) {
+			compiler_ld = compiler_cpp;
+		}
+
 		requires_relink++;
 	}
 
@@ -728,8 +754,8 @@ cli_build_asset(char *fpath, struct dirent *dp)
 		*(ext)++ = '\0';
 		cli_write_asset(name, ext);
 		*ext = '_';
-		
-		cli_add_cfile(name, cpath, opath, &st, 0);
+
+		cli_add_source_file(name, cpath, opath, &st, BUILD_NOBUILD);
 		kore_mem_free(name);
 		return;
 	}
@@ -788,17 +814,17 @@ 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);
+	cli_add_source_file(name, cpath, opath, &st, BUILD_C);
 	kore_mem_free(name);
 }
 
 static void
-cli_add_cfile(char *name, char *fpath, char *opath, struct stat *st,
+cli_add_source_file(char *name, char *fpath, char *opath, struct stat *st,
     int build)
 {
 	struct cfile		*cf;
 
-	cfiles_count++;
+	source_files_count++;
 	cf = kore_malloc(sizeof(*cf));
 
 	cf->st = *st;
@@ -811,10 +837,11 @@ cli_add_cfile(char *name, char *fpath, char *opath, struct stat *st,
 }
 
 static void
-cli_register_cfile(char *fpath, struct dirent *dp)
+cli_register_source_file(char *fpath, struct dirent *dp)
 {
 	struct stat		st;
 	char			*ext, *opath;
+	int			build;
 
 	if ((ext = strrchr(fpath, '.')) == NULL ||
 	    (strcmp(ext, ".c") && strcmp(ext, ".cpp")))
@@ -825,11 +852,15 @@ cli_register_cfile(char *fpath, struct dirent *dp)
 
 	(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);
-		return;
+		build = BUILD_NOBUILD;
+	} else if (!strcmp(ext, ".cpp")) {
+		build = BUILD_CXX;
+		cxx_files_count++;
+	} else {
+		build = BUILD_C;
 	}
 
-	cli_add_cfile(dp->d_name, fpath, opath, &st, 1);
+	cli_add_source_file(dp->d_name, fpath, opath, &st, build);
 }
 
 static void
@@ -979,17 +1010,36 @@ cli_generate_certs(void)
 }
 
 static void
-cli_compile_cfile(void *arg)
+cli_compile_source_file(void *arg)
 {
 	int		idx, i;
 	struct cfile	*cf = arg;
 	char		*args[32 + CFLAGS_MAX];
+	char		*compiler;
+	char		**flags;
+	int		flags_count;
+
+	switch (cf->build) {
+		case BUILD_C:
+			compiler = compiler_c;
+			flags = cflags;
+			flags_count = cflags_count;
+			break;
+		case BUILD_CXX:
+			compiler = compiler_cpp;
+			flags = cxxflags;
+			flags_count = cxxflags_count;
+			break;
+		default:
+			cli_fatal("cli_compile_file: unexpected file type: %d", cf->build);
+			break;
+	}
 
 	idx = 0;
 	args[idx++] = compiler;
 
-	for (i = 0; i < cflags_count; i++)
-		args[idx++] = cflags[i];
+	for (i = 0; i < flags_count; i++)
+		args[idx++] = flags[i];
 
 	args[idx++] = "-c";
 	args[idx++] = cf->fpath;
@@ -1006,12 +1056,12 @@ cli_link_library(void *arg)
 	struct cfile		*cf;
 	int			idx, i;
 	char			*libname;
-	char			*args[cfiles_count + 11 + LD_FLAGS_MAX];
+	char			*args[source_files_count + 11 + LD_FLAGS_MAX];
 
 	(void)cli_vasprintf(&libname, "%s/%s.so", rootdir, appl);
 
 	idx = 0;
-	args[idx++] = compiler;
+	args[idx++] = compiler_ld;
 
 	TAILQ_FOREACH(cf, &source_files, list)
 		args[idx++] = cf->opath;
@@ -1023,7 +1073,7 @@ cli_link_library(void *arg)
 	args[idx++] = libname;
 	args[idx] = NULL;
 
-	execvp(compiler, args);
+	execvp(compiler_ld, args);
 }
 
 static void
@@ -1087,6 +1137,8 @@ parse_option:
 
 		if (!strcasecmp(p, "cflags")) {
 			cli_buildopt_cflags(bopt, t);
+		} else if (!strcasecmp(p, "cxxflags")) {
+			cli_buildopt_cxxflags(bopt, t);
 		} else if (!strcasecmp(p, "ldflags")) {
 			cli_buildopt_ldflags(bopt, t);
 		} else {
@@ -1102,6 +1154,7 @@ cli_buildopt_new(const char *name)
 
 	bopt = kore_malloc(sizeof(*bopt));
 	bopt->cflags = NULL;
+	bopt->cxxflags = NULL;
 	bopt->ldflags = NULL;
 	bopt->name = kore_strdup(name);
 
@@ -1133,6 +1186,8 @@ cli_buildopt_cleanup(void)
 
 		if (bopt->cflags != NULL)
 			kore_buf_free(bopt->cflags);
+		if (bopt->cxxflags != NULL)
+			kore_buf_free(bopt->cxxflags);
 		if (bopt->ldflags != NULL)
 			kore_buf_free(bopt->ldflags);
 		kore_mem_free(bopt);
@@ -1154,6 +1209,20 @@ cli_buildopt_cflags(struct buildopt *bopt, const char *string)
 }
 
 static void
+cli_buildopt_cxxflags(struct buildopt *bopt, const char *string)
+{
+	if (bopt == NULL) {
+		if ((bopt = cli_buildopt_find("_default")) == NULL)
+			cli_fatal("no _default build options");
+	}
+
+	if (bopt->cxxflags == NULL)
+		bopt->cxxflags = kore_buf_create(128);
+
+	kore_buf_appendf(bopt->cxxflags, "%s ", string);
+}
+
+static void
 cli_buildopt_ldflags(struct buildopt *bopt, const char *string)
 {
 	if (bopt == NULL) {
@@ -1168,38 +1237,44 @@ cli_buildopt_ldflags(struct buildopt *bopt, const char *string)
 }
 
 static void
-cli_build_cflags(struct buildopt *bopt)
+cli_build_flags_common(struct kore_buf* buf)
 {
-	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,
+	kore_buf_appendf(buf,
 	    "-fPIC -I%s/src -I%s/src/includes ", rootdir, rootdir);
 #if defined(PREFIX)
-	kore_buf_appendf(bopt->cflags, "-I%s/include ", PREFIX);
+	kore_buf_appendf(buf, "-I%s/include ", PREFIX);
 #else
-	kore_buf_appendf(bopt->cflags, "-I/usr/local/include ");
+	kore_buf_appendf(buf, "-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 ");
+	kore_buf_appendf(buf, "-I/opt/local/include ");
+	kore_buf_appendf(buf, "-I/usr/local/opt/openssl/include ");
 #endif
 #if defined(KORE_USE_PGSQL)
-	kore_buf_appendf(bopt->cflags, "-I%s ", PGSQL_INCLUDE_PATH);
+	kore_buf_appendf(buf, "-I%s ", PGSQL_INCLUDE_PATH);
 #endif
 #if defined(KORE_NO_HTTP)
-	kore_buf_appendf(bopt->cflags, "-DKORE_NO_HTTP ");
+	kore_buf_appendf(buf, "-DKORE_NO_HTTP ");
 #endif
 #if defined(KORE_NO_TLS)
-	kore_buf_appendf(bopt->cflags, "-DKORE_NO_TLS ");
+	kore_buf_appendf(buf, "-DKORE_NO_TLS ");
 #endif
+}
+
+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);
+
+	cli_build_flags_common(bopt->cflags);
 
 	if (obopt != NULL && obopt->cflags != NULL) {
 		kore_buf_append(bopt->cflags, obopt->cflags->data,
@@ -1212,6 +1287,31 @@ cli_build_cflags(struct buildopt *bopt)
 }
 
 static void
+cli_build_cxxflags(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->cxxflags == NULL)
+		bopt->cxxflags = kore_buf_create(128);
+
+	cli_build_flags_common(bopt->cxxflags);
+
+	if (obopt != NULL && obopt->cxxflags != NULL) {
+		kore_buf_append(bopt->cxxflags, obopt->cxxflags->data,
+		    obopt->cxxflags->offset);
+	}
+
+	string = kore_buf_stringify(bopt->cxxflags, NULL);
+	if (cxx_files_count > 0)
+		printf("CXXFLAGS=%s\n", string);
+	cxxflags_count = kore_split_string(string, " ", cxxflags, CXXFLAGS_MAX);
+}
+
+static void
 cli_build_ldflags(struct buildopt *bopt)
 {
 	struct buildopt		*obopt;