aboutsummaryrefslogblamecommitdiff
path: root/make.c
blob: 251ca5c1d124206712376331eee7ed081207d99a (plain) (tree)
1
2
3
4
5
6
7
8
                   
                  



                     
                   



                   


                               
                



















                                                                 

                                 









                                       
     
                 
      
              
 









                             
 

                           
                            

                                  
 
                                                        
                              
                         



                                                                
                                           
                        
                                                        




                       













                                                                                
                         



                                                                      
                 
 

                                    
 


























                                                                                      
 
                               



                            
                
 






                                                                                            
         








                                              
 













                                                       
 
#define _GNU_SOURCE
#include <errno.h>
#include <glob.h>
#include <langinfo.h>
#include <libgen.h>
#include <locale.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#if __has_include(<features.h>)
#	include <features.h>
#endif

#include "cbs.h"

#define flagset(o) (flags & UINT32_C(1)<<(o)-'a')

[[noreturn, gnu::format(printf, 1, 2)]]
static void err(const char *, ...);
static void build_mlib(void);

static uint32_t flags;
static const char *argv0;

static char *cflags_req[] = {
	"-Wall",
	"-Wextra",
	"-Wpedantic",
	"-Wvla",
	"-Wno-attributes",
	"-Wno-empty-body",          /* Annoying when debugging */
	"-Wno-pointer-sign",
	"-Wno-parentheses",
	"-Ivendor/mlib/include",
	"-pipe",
	"-std=c23",
#ifdef __linux__
	"-D_FILE_OFFSET_BITS=64",
#endif
#ifdef __GLIBC__
	"-D_GNU_SOURCE",
#endif
	"-DPCRE2_CODE_UNIT_WIDTH=8",
};

static char *cflags_dbg[] = {
	"-DDEBUG=1",
	"-fsanitize=address,undefined",
#if __GNUC__ && __APPLE__
	"-ggdb2",
#else
	"-ggdb3",
#endif
	"-O0",
};

static char *cflags_rls[] = {
	"-DNDEBUG=1",
	"-flto",
#ifdef __APPLE__
	"-mcpu=native",
#else
	"-march=native",
	"-mtune=native",
#endif
	"-O3",
};

int
main(int argc, char **argv)
{
	cbsinit(argc, argv);
	rebuild();
	setlocale(LC_ALL, "");

	argv0 = basename(argv[0]);

	int opt;
	while ((opt = getopt(argc, argv, "mr")) != -1) {
		switch (opt) {
		case '?':
usage:
			fprintf(stderr,
				"Usage: %s [-mr]\n"
				"       %s clean | distclean\n",
				*argv, *argv);
			exit(EXIT_FAILURE);
		default:
			flags |= UINT32_C(1) << opt-'a';
		}
	}

	argc -= optind;
	argv += optind;

	if (argc > 1)
		goto usage;

	if (argc == 1) {
		struct strs cmd = {};
		if (strcmp(argv[0], "clean") == 0) {
			strspushl(&cmd, "rm", "-f", "grab", "git-grab");
		} else if (strcmp(argv[0], "distclean") == 0) {
			strspushl(&cmd, "rm", "-f", "grab", "git-grab", "make");
			if (fexists("vendor/mlib/make")) {
				cmdput(cmd);
				if (cmdexec(cmd) != EXIT_SUCCESS)
					exit(EXIT_FAILURE);
				strszero(&cmd);
				strspushl(&cmd, "vendor/mlib/make", "clean");
			}
		} else {
			err(strcmp(nl_langinfo(CODESET), "UTF-8") == 0
				? "invalid subcommand — ‘%s’"
				: "invalid subcommand -- `%s'",
				argv[0]);
		}

		cmdput(cmd);
		return cmdexec(cmd);
	}

	build_mlib();

	glob_t g;
	if (glob("src/*.c", 0, nullptr, &g))
		err("glob:");

	struct strs cmd = {};
	for (char ch = '0'; ch <= '1'; ch++) {
		strspushenvl(&cmd, "CC", "cc");
		strspush(&cmd, cflags_req, lengthof(cflags_req));
		if (flagset('r'))
			strspushenv(&cmd, "CFLAGS", cflags_rls, lengthof(cflags_rls));
		else
			strspushenv(&cmd, "CFLAGS", cflags_dbg, lengthof(cflags_dbg));

		char buf[] = "-DGIT_GRAB=X";
		buf[sizeof(buf) - 2] = ch;
		strspushl(&cmd, buf);

		if (!pcquery(&cmd, "libpcre2-8", PC_CFLAGS | PC_LIBS))
			strspushl(&cmd, "-lpcre2-8");

		strspushl(&cmd, "-o", ch == '0' ? "grab" : "git-grab");
		strspush(&cmd, g.gl_pathv, g.gl_pathc);
		strspushl(&cmd, "vendor/mlib/libmlib.a");
		cmdput(cmd);
		if (cmdexec(cmd) != EXIT_SUCCESS)
			exit(EXIT_FAILURE);

		strszero(&cmd);
	}

	return EXIT_SUCCESS;
}

void
build_mlib(void)
{
	struct strs cmd = {};
	if (flagset('m') || !fexists("vendor/mlib/make")) {
		strspushenvl(&cmd, "CC", "cc");
		strspushl(&cmd, "-std=c23", "-o", "vendor/mlib/make", "vendor/mlib/make.c");
		cmdput(cmd);
		if (cmdexec(cmd) != EXIT_SUCCESS)
			exit(EXIT_FAILURE);
		strszero(&cmd);
	}
	strspushl(&cmd, "./vendor/mlib/make");
	if (flagset('m'))
		strspushl(&cmd, "-f");
	if (flagset('r'))
		strspushl(&cmd, "-r");
	cmdput(cmd);
	if (cmdexec(cmd) != EXIT_SUCCESS)
		exit(EXIT_FAILURE);
	strsfree(&cmd);
}

void
err(const char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	int save = errno;
	flockfile(stderr);
	fprintf(stderr, "%s: ", argv0);
	vfprintf(stderr, fmt, ap);
	if (fmt[strlen(fmt) - 1] == ':')
		fprintf(stderr, " %s", strerror(save));
	fputc('\n', stderr);
	funlockfile(stderr);
	va_end(ap);
	exit(EXIT_FAILURE);
}