summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.assets/bop.pngbin0 -> 3808 bytes
-rw-r--r--.gitignore3
-rw-r--r--Makefile17
-rw-r--r--README20
-rw-r--r--README.md20
-rw-r--r--core/.bop/posthook.sh1
-rw-r--r--core/bop.c122
-rw-r--r--core/build.c184
-rw-r--r--core/hook.c51
-rw-r--r--dev/build.env1
-rw-r--r--head/bop/build.h18
-rw-r--r--head/bop/common.h21
-rw-r--r--head/bop/hook.h18
13 files changed, 476 insertions, 0 deletions
diff --git a/.assets/bop.png b/.assets/bop.png
new file mode 100644
index 0000000..555f363
--- /dev/null
+++ b/.assets/bop.png
Binary files differ
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 $@
diff --git a/README b/README
new file mode 100644
index 0000000..14e9847
--- /dev/null
+++ b/README
@@ -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
+
+![bop](./assets/bop.png)
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
+
+![bop](https://git.faracom.org/chloe/bop/raw/branch/main/.assets/bop.png)
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(&params, sizeof(params));
+ while ((dirent = readdir(dir)) != NULL) {
+ if (dirent->d_name[0] == '.') {
+ continue;
+ }
+
+ error = compile(dirpath, dirent, &params);
+ 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 */