diff options
| -rw-r--r-- | .assets/bop.png | bin | 0 -> 3808 bytes | |||
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | Makefile | 17 | ||||
| -rw-r--r-- | README | 20 | ||||
| -rw-r--r-- | README.md | 20 | ||||
| -rw-r--r-- | core/.bop/posthook.sh | 1 | ||||
| -rw-r--r-- | core/bop.c | 122 | ||||
| -rw-r--r-- | core/build.c | 184 | ||||
| -rw-r--r-- | core/hook.c | 51 | ||||
| -rw-r--r-- | dev/build.env | 1 | ||||
| -rw-r--r-- | head/bop/build.h | 18 | ||||
| -rw-r--r-- | head/bop/common.h | 21 | ||||
| -rw-r--r-- | head/bop/hook.h | 18 |
13 files changed, 476 insertions, 0 deletions
diff --git a/.assets/bop.png b/.assets/bop.png Binary files differnew file mode 100644 index 0000000..555f363 --- /dev/null +++ b/.assets/bop.png diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..68135d1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/bop +*.o +*.d diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fd618b5 --- /dev/null +++ b/Makefile @@ -0,0 +1,17 @@ +CFILES = $(shell find core/ -name "*.c") +OFILES = $(CFILES:.c=.o) +DFILES = $(CFILES:.c=.d) + +CC = clang +CFLAGS = -Wall -pedantic -Ihead + +.PHONY: all +all: bop + +.PHONY: bop +bop: $(OFILES) + $(CC) $(OFILES) -o $@ + +-include $(DFILES) +%.o: %.c + $(CC) -c $(CFLAGS) $< -o $@ @@ -0,0 +1,20 @@ +# Bop is a quick and minimal build utility to serve as an alternative to MAKE + +## Hooks + +# Hooks may be placed in the target build directory as such: + +``` +$TARGET/.bop/posthook.sh - Runs after the build +$TARGET/.bop/prehook.sh - Runs before the build +``` + +To build a directory with CFILES, run: + +``` +user@host~$ : BOP_BUILD=$TARGET bop build +``` + +## Screenshot and example + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..d9be184 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# Bop is a quick and minimal build utility to serve as an alternative to MAKE + +## Hooks + +# Hooks may be placed in the target build directory as such: + +``` +$TARGET/.bop/posthook.sh - Runs after the build +$TARGET/.bop/prehook.sh - Runs before the build +``` + +To build a directory with CFILES, run: + +``` +user@host~$ : BOP_BUILD=$TARGET bop build +``` + +## Screenshot and example + + diff --git a/core/.bop/posthook.sh b/core/.bop/posthook.sh new file mode 100644 index 0000000..05f3860 --- /dev/null +++ b/core/.bop/posthook.sh @@ -0,0 +1 @@ +clang $BOP_PROJECT_ROOT/core/*.o -o bop diff --git a/core/bop.c b/core/bop.c new file mode 100644 index 0000000..02c0324 --- /dev/null +++ b/core/bop.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2026, Chloe M., et al. + * Provided under the BSD-3 clause. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include "bop/common.h" +#include "bop/hook.h" +#include "bop/build.h" + +static void +version(void) +{ + printf("Version: %s\n", BOP_VERSION); +} + +static void +help(void) +{ + printf("usage: %s=<dir> ./bop [flags] [build_op]\n", BOP_BUILD_ENV); + printf("-- flags --\n"); + printf("[-h] Display this help menu\n"); + printf("[-v] Display the version\n"); + printf("-- build operations\n"); + printf("[build] Build the directory specified by %s\n", BOP_BUILD_ENV); +} + +/* + * Discover any possible hooks to be ran in the desired build directory and + * begin the build process. + */ +static int +run_build(void) +{ + char pathbuf[256]; + char *build_dir; + int error; + + build_dir = getenv(BOP_BUILD_ENV); + if (build_dir == NULL) { + printf("fatal: build directory not specified in %s\n", BOP_BUILD_ENV); + return -1; + } + + /* + * There is a pre-build hook to be located within the [BUILD_DIR]/.bop/prehook.sh which + * is simply a shell script to be executed. + */ + snprintf(pathbuf, sizeof(pathbuf), "%s/.bop/prehook.sh", build_dir); + if (access(pathbuf, F_OK) == 0) { + bop_shell_hook(pathbuf); + } + + error = bop_build_dir(build_dir); + if (error < 0) { + printf("fatal: failed to build '%s'\n", build_dir); + return error; + } + + /* Run the post hook if we can */ + snprintf(pathbuf, sizeof(pathbuf), "%s/.bop/posthook.sh", build_dir); + if (access(pathbuf, F_OK) == 0) { + bop_shell_hook(pathbuf); + } + + return 0; +} + +static int +do_build_op(const char *op) +{ + if (op == NULL) { + return -1; + } + + switch (*op) { + case 'b': + if (strcmp(op, "build") == 0) { + return run_build(); + } + + break; + } + + return -1; +} + +int +main(int argc, char **argv) +{ + int opt; + char *build_opt; + + if (argc < 2) { + printf("fatal: too few arguments\n"); + help(); + return -1; + } + + while ((opt = getopt(argc, argv, "hv")) != -1) { + switch (opt) { + case 'h': + help(); + return -1; + case 'v': + version(); + return -1; + } + } + + if (optind >= argc) { + printf("fatal: please specify a build operation\n"); + help(); + return -1; + } + + build_opt = argv[optind++]; + return do_build_op(build_opt); +} diff --git a/core/build.c b/core/build.c new file mode 100644 index 0000000..78ad65a --- /dev/null +++ b/core/build.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2026, Chloe M., et al. + * Provided under the BSD-3 clause. + */ + +#include <sys/wait.h> +#include <dirent.h> +#include <stdint.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdbool.h> +#include <strings.h> +#include <unistd.h> +#include <string.h> +#include <stdio.h> +#include "bop/common.h" +#include "bop/build.h" + +/* + * Build parameters + * + * @cflags: List of CFLAGS + * + * TODO: Use this instead of BOP_DEFAULT_CFLAGS and similar + */ +struct build_params { + char **cflags; +}; + +/* + * Obtain the file extension of a file + * + * @filename: Filename to obtain extension of + */ +static const char * +get_extension(const char *filename) +{ + const char *p; + bool have_dot = false; + + if (filename == NULL) { + return NULL; + } + + p = filename; + while (*p != '\0') { + if (*p == '.') { + have_dot = true; + } else if (have_dot) { + --p; + return p; + } + ++p; + } + + return NULL; +} + +/* + * Truncate a file extension + * + * @filename: Filename to truncate file extension from + * + * XXX: Returns memory allocated with strdup(), remember to free! + */ +static char * +trunc_extension(const char *filename) +{ + char *p, *p1; + + if ((p = strdup(filename)) == NULL) { + return NULL; + } + + p1 = p; + while (*p1 != '\0') { + if (*p1 == '.') { + *p1 = '\0'; + return p; + } + ++p1; + } + + free(p); + return NULL; +} + +static int +invoke_cc(const char *cfile_path, struct build_params *params) +{ + pid_t child; + int status; + char *trunc_ext; + char outpath[256]; + + if (cfile_path == NULL || params == NULL) { + return -1; + } + + trunc_ext = trunc_extension(cfile_path); + if (trunc_ext == NULL) { + return -1; + } + + snprintf(outpath, sizeof(outpath), "%s.o", trunc_ext); + child = fork(); + if (child == 0) { + execl(BOP_CC, BOP_CC, "-c", cfile_path, "-o", outpath, BOP_DEFAULT_CFLAGS, NULL); + } else { + waitpid(child, &status, 0); + free(trunc_ext); + return status; + } + + return -1; +} + +static int +compile(const char *dirpath, struct dirent *dirent, struct build_params *params) +{ + const char *filename, *ext; + char pathbuf[256]; + int error; + + if (dirpath == NULL || dirent == NULL) { + return -1; + } + + /* Ignore non regulars */ + if (dirent->d_type != DT_REG) { + return 0; + } + + filename = dirent->d_name; + ext = get_extension(filename); + + /* Ignore files with no extensions */ + if (ext == NULL) { + return 0; + } + + snprintf(pathbuf, sizeof(pathbuf), "%s/%s", dirpath, filename); + + /* Build all CFILES */ + if (strcmp(ext, ".c") == 0) { + error = invoke_cc(pathbuf, params); + if (error < 0) + printf("fatal: cc invocation failure\n"); + return error; + } + + return 0; + +} + +int +bop_build_dir(const char *dirpath) +{ + struct build_params params; + struct dirent *dirent; + DIR *dir; + int error; + + dir = opendir(dirpath); + if (dir == NULL) { + perror("opendir"); + return -1; + } + + bzero(¶ms, sizeof(params)); + while ((dirent = readdir(dir)) != NULL) { + if (dirent->d_name[0] == '.') { + continue; + } + + error = compile(dirpath, dirent, ¶ms); + if (error < 0) { + printf("fatal: failed to build '%s'\n", dirent->d_name); + return error; + } + } + + return 0; +} diff --git a/core/hook.c b/core/hook.c new file mode 100644 index 0000000..b915901 --- /dev/null +++ b/core/hook.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2026, Chloe M., et al. + * Provided under the BSD-3 clause. + */ + +#include <sys/wait.h> +#include <unistd.h> +#include "bop/hook.h" + +/* Shell we use by default */ +#define DEFAULT_SHELL_PATH "/bin/sh" + +/* + * Execute the shell for a specific shell script + * + * @script_path: Path of shell script + */ +static void +exec_shell_for(const char *script_path) +{ + if (script_path == NULL) { + return; + } + + execl(DEFAULT_SHELL_PATH, DEFAULT_SHELL_PATH, script_path, NULL); +} + +/* + * Run a shell hook with POSIX sh + * + * XXX: Maybe support '#!/bin/xxx'? + */ +int +bop_shell_hook(const char *hook_path) +{ + pid_t child; + int status; + + if (hook_path == NULL) { + return -1; + } + + child = fork(); + if (child == 0) { + exec_shell_for(hook_path); + } else { + waitpid(child, &status, 0); + } + + return 0; +} diff --git a/dev/build.env b/dev/build.env new file mode 100644 index 0000000..577ffe3 --- /dev/null +++ b/dev/build.env @@ -0,0 +1 @@ +export BOP_PROJECT_ROOT=$PWD diff --git a/head/bop/build.h b/head/bop/build.h new file mode 100644 index 0000000..ff4c8e5 --- /dev/null +++ b/head/bop/build.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2026, Chloe M., et al. + * Provided under the BSD-3 clause. + */ + +#ifndef BOP_BUILD_H +#define BOP_BUILD_H 1 + +/* + * Build a directory + * + * @dirpath: Directory to build + * + * Returns zeron on success + */ +int bop_build_dir(const char *dirpath); + +#endif /* !BOP_BUILD_H */ diff --git a/head/bop/common.h b/head/bop/common.h new file mode 100644 index 0000000..4e41a1e --- /dev/null +++ b/head/bop/common.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2026, Chloe M., et al. + * Provided under the BSD-3 clause. + */ + +#ifndef BOP_COMMON_H +#define BOP_COMMON_H 1 + +/* ENV for bop build directory */ +#define BOP_BUILD_ENV "BOP_BUILD" + +/* BOP version */ +#define BOP_VERSION "v0.0.1" + +/* Default BOP cflags */ +#define BOP_DEFAULT_CFLAGS "-Wall", "-pedantic", "-Ihead" + +/* Default C compiler */ +#define BOP_CC "/usr/bin/clang" + +#endif /* !BOP_COMMON_H */ diff --git a/head/bop/hook.h b/head/bop/hook.h new file mode 100644 index 0000000..d78f2d7 --- /dev/null +++ b/head/bop/hook.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2026, Chloe M., et al. + * Provided under the BSD-3 clause. + */ + +#ifndef BOP_HOOK_H +#define BOP_HOOK_H 1 + +/* + * Run a shell script build hook + * + * @hook_path: Path to hook + * + * Returns zero on success + */ +int bop_shell_hook(const char *hook_path); + +#endif /* !BOP_HOOK_H */ |
