commit fdaf28d9eec999deef4b0ae67ed6b0106a26041e
parent 64a1c9cb7d8bbc3934115dc13c72e45afa85a2e8
Author: Bharatvaj Hemanth <bharatvaj@yahoo.com>
Date: Thu, 4 Jul 2024 04:10:15 +0530
Add support for selecting build systems with exts
Remove enum and use macros for general ease of use.
Diffstat:
M | LICENSE | | | 0 | |
M | Makefile | | | 9 | ++++++--- |
M | README | | | 12 | +++++++++--- |
M | config.h | | | 71 | +++++++++++++++++++++++++++++++---------------------------------------- |
M | fmake.c | | | 103 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------- |
A | todo.txt | | | 21 | +++++++++++++++++++++ |
6 files changed, 154 insertions(+), 62 deletions(-)
diff --git a/LICENSE b/LICENSE
diff --git a/Makefile b/Makefile
@@ -1,14 +1,17 @@
-include config.mk
+VERSION = 0.1.3
+
+CFLAGS += -DFMAKE_VERSION=$(VERSION) -Wall -Wextra -g
+PREFIX ?= /usr/local
all: fmake
-fmake: fmake.c
+fmake: fmake.c config.h
clean:
rm -f fmake
install: fmake
- mkdir -p $(DESTDIR)$(PREFIX)/bin
+ mkdir -p $(DESTDIR)$(PREFIX)/bin
cp -f fmake $(DESTDIR)$(PREFIX)/bin
chmod 755 $(DESTDIR)$(PREFIX)/bin/fmake
diff --git a/README b/README
@@ -14,9 +14,12 @@ Opinionates build directory as 'out' in case of no clear build 'out' directory s
USAGE
-----
-To avoid complexity, fmake does not fork any process to run the commands. It just prints out the right command.
-`alias make='$(fmake)'` should be added in your .bash_profile, or .zshrc for fmake to work.
+Just type fmake, in your project directory.
+
+ alias m=fmake -a
+
+to quickly run fmake commands.
When none is found, it just defaults to the `make` in $PATH
@@ -28,4 +31,7 @@ Supported build files
* configure
* gradle
* ninja
-* Much more to be added soon
+* nobuild,
+* and much more!
+
+Find the complete list in config.h
diff --git a/config.h b/config.h
@@ -1,47 +1,38 @@
-#include <stdint.h>
-
-typedef enum {
- FMAKE_POSIX_MAKEFILE,
- FMAKE_GNU_MAKEFILE,
- FMAKE_BSD_MAKEFILE,
- FMAKE_NINJA,
- FMAKE_O_MAKEFILE,
- FMAKE_CONFIGURE,
- FMAKE_AUTORECONF,
- FMAKE_CMAKE,
- FMAKE_GN,
- FMAKE_NPM,
- FMAKE_RUST,
- FMAKE_PIP,
- FMAKE_GRADLE,
-} maker_t;
+#define BUILD_SYSTEMS \
+ X(0, "Makefile" , "make") \
+ X(0, "makefile" , "make") \
+ X(0, "GNUMakefile" , "gmake") \
+ X(0, "BSDMakefile" , "bmake") \
+ X(1, "pro" , "qmake") \
+ X(0, "make" , "sh" , "make") \
+ X(0, "build.sh" , "sh" , "build.sh") \
+ X(0, "build.ninja" , "ninja") \
+ X(0, "OMakefile" , "omake") \
+ X(0, "configure" , "sh" , "configure") \
+ X(0, "configure.ac" , "autoreconf" , "-fiv") \
+ X(0, "CMakeLists.txt" , "cmake" , "-B" , "out/") \
+ X(0, "BUILD.gn" , "gn" , "gen" , "out/") \
+ X(0, "nob" , "./nob" , "./nob") \
+ X(0, "nob.c" , "cc" , "cc" , "./nob.c" , "-o" , "nob") \
+ X(0, "nobuild" , "./nobuild" , ) \
+ X(0, "nobuild.c" , "cc" , "./nobuild.c" , "-o" , "nobuild") \
+ X(0, "package.json" , "npm" , "run") \
+ X(0, "Cargo.toml" , "cargo" , "build") \
+ X(0, "setup.py" , "pip" , "install" , ".") \
+ X(0, "gradlew.bat" , "./gradlew.bat" , "./gradlew.bat") \
+ X(0, "gradlew" , "sh" , "gradlew") \
+ X(0, "PKGBUILD" , "makepkg" , "-i")
typedef struct {
- const char* filename;
- maker_t type;
- const char* cmd;
- const char* args;
+short check_extension;
+const char* filename;
+const char* cmd;
+const char* args[256];
} maker_config_t;
static const maker_config_t makers[] = {
-{ "Makefile", FMAKE_POSIX_MAKEFILE, "make", "" },
-{ "makefile", FMAKE_POSIX_MAKEFILE, "make", "" },
-{ "GNUMakefile", FMAKE_GNU_MAKEFILE, "gmake", "" },
-{ "BSDMakefile", FMAKE_BSD_MAKEFILE, "bmake", "" },
-{ "build.ninja", FMAKE_NINJA, "ninja", "" },
-{ "OMakefile", FMAKE_O_MAKEFILE, "omake", "" },
-{ "configure", FMAKE_CONFIGURE, "sh", "configure" },
-{ "configure.ac", FMAKE_AUTORECONF, "autoreconf", "-i" },
-{ "CMakeLists.txt", FMAKE_CMAKE, "cmake", "-B out" },
-{ "BUILD.gn", FMAKE_GN, "gn", "gen out" },
-{ "package.json", FMAKE_NPM, "npm", "install" },
-{ "Cargo.toml", FMAKE_RUST, "cargo", "install" },
-{ "setup.py", FMAKE_PIP, "pip", "install ." },
-#ifdef _WIN32
-{ "gradlew.bat", FMAKE_GRADLE, "./gradlew.bat", "" },
-#endif
-{ "gradlew", FMAKE_GRADLE, "sh", "gradlew" },
+#define X(ISEXT, LOOKFOR, CMD, ...) {ISEXT, LOOKFOR, CMD, { CMD, __VA_ARGS__} },
+BUILD_SYSTEMS
+#undef X
};
-static maker_config_t maker;
-
diff --git a/fmake.c b/fmake.c
@@ -1,30 +1,101 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
#include "config.h"
-void process_build() {
- printf("%s %s", maker.cmd, maker.args);
-}
+static maker_config_t maker;
+static DIR *dir;
+static struct dirent *entry;
+static short should_execute_commands = 0;
+static short is_accepting_cmd_args = 0;
+
+
+#define info(...) \
+ if (should_execute_commands) { \
+ fprintf(stderr, __VA_ARGS__); \
+ }
-struct stat st = {0};
-void process_string() {
- for (int i = 0; i < (sizeof(makers) / sizeof(maker_config_t)); i++) {
- const char* filename = makers[i].filename;
- if (!stat(filename, &st)) {
- maker = makers[i];
- process_build();
- return;
+int process_build(char* argv[]) {
+ int status = -1;
+ info("++");
+ for(size_t i = 0; i < sizeof(maker.args) && maker.args[i] != NULL; i++) {
+ fprintf(should_execute_commands? stderr : stdout , " %s", maker.args[i]);
+ }
+ info("\n");
+ if (should_execute_commands) {
+ fflush(stderr);
+ if (*maker.args[0] == '\0') {
+ status = execlp(maker.cmd, maker.cmd, '\0', (void*)0);
+ }
+ else {
+ status = execvp(maker.cmd, (char* const*)maker.args);
+ }
+ if (status == -1) {
+ printf("Error: %d\n", status);
}
}
- maker = makers[FMAKE_POSIX_MAKEFILE];
- process_build();
+ return status;
}
int main(int argc, char* argv[]) {
- process_string();
- return -1;
+ int i;
+ for(i = 1; i < argc; i++) {
+ if (!(argv[i][0] == '-' && argv[i][1] != '\0')) {
+ printf("Usage: fmake [-l]\n");
+ exit(-1);
+ }
+ switch(argv[i][1]) {
+ case '-':
+ is_accepting_cmd_args = 1;
+ goto FMAKE_AFTER_ARG_CHECK;
+ break;
+ case 'l':
+ // TODO show better listing
+ /* list supported build systems */
+ for (size_t i = 0; i < (sizeof(makers) / sizeof(maker_config_t)); i++) {
+ printf("%s\n", makers[i].cmd);
+ }
+ break;
+ case 'a':
+ should_execute_commands = 1;
+ break;
+ }
+ }
+FMAKE_AFTER_ARG_CHECK:
+ argc = i;
+ argv = argv + i;
+ for (size_t i = 0; i < (sizeof(makers) / sizeof(maker_config_t)); i++) {
+ if (makers[i].check_extension) {
+ // TODO optimize this code
+ // FIXME it's not sure if the '.' is found from first or last
+ // last should be preferred
+ dir = opendir("./");
+ if (dir == NULL) {
+ perror("fmake:");
+ return -1;
+ }
+ while ((entry = readdir(dir)) != NULL) {
+ if (entry->d_type == DT_REG) {
+ char* dot = strrchr(entry->d_name, '.');
+ if (dot && strcmp(dot + 1, makers[i].filename) == 0) {
+ maker = makers[i];
+ return process_build(argv);
+ }
+ }
+ }
+ printf("extension check %s\n", makers[i].filename);
+ } else {
+ const char* filename = makers[i].filename;
+ if (access(filename, F_OK) == 0) {
+ maker = makers[i];
+ return process_build(argv);
+ }
+ }
+ }
+ maker = makers[0];
+ return process_build(argv);
}
diff --git a/todo.txt b/todo.txt
@@ -0,0 +1,21 @@
+fmake uses chains.
+
+CHAINS
+------
+Chains are created for build tools which require the user to execute multiple commands in order to execute the build.
+
+Example
+-------
+ cmake -Bout -S. -GNinja
+ cd out
+ ninja
+
+
+This can be defined in the config.txt as,
+
+FM_CMAKE->FM_NINJA
+
+Another example is confiure
+FM_AUTORECONF->FM_AUTOCONF
+FM_AUTOCONF->FM_MAKE
+