commit 40784be9f20d5d9695debac30a044070d53f83d9
Author: Jan Pobrislo <ccx@te2000.cz>
Date: Mon, 3 Mar 2025 13:34:23 +0000
Initial commit; working single executable build.
Diffstat:
7 files changed, 117 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,2 @@
+*.sw[op]
+build
diff --git a/Makefile b/Makefile
@@ -0,0 +1,9 @@
+all: all_executables
+.PHONY: all
+
+executables:=hello
+include simplelink.mk
+
+clean:
+ rm -r build
+.PHONY: clean
diff --git a/scripts/cc b/scripts/cc
@@ -0,0 +1,5 @@
+#!/bin/sh -xe
+exec gcc -D_GNU_SOURCE -Werror \
+ -pipe -std=c11 -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -ffunction-sections -fdata-sections \
+ "$@" -static -g
+# -Wall
diff --git a/scripts/codedeps.awk b/scripts/codedeps.awk
@@ -0,0 +1,56 @@
+BEGIN {
+ if(length(target) == 0 || length(srcname) == 0) {
+ exit 2
+ }
+}
+
+/^# [0-9]+ "[^"]+"( [0-9]+)*$/ && $3 !~ /^"[<\/]/ {
+ inc[$3]=1
+}
+
+/^\/\/ \{IMP\} /{
+ imp[substr($0,10)]
+}
+
+function depname(s) {
+ sub(/"$/, "", s)
+ sub(/^"/, "", s)
+ return s
+}
+
+function deparray(fname) {
+ gsub(/[^a-zA-Z0-9_]/, "__", fname)
+ return "LINKDEP_" fname
+}
+
+function objfile(fname) {
+ sub(/\.c$/, ".o", fname)
+ return "build/" fname
+}
+
+END {
+ da = deparray(srcname)
+ printf "ifndef %s\n\n", da
+ printf "%s:", target
+ for(f in inc) {
+ printf " %s", depname(f)
+ }
+ printf "\n\n"
+ printf "%s:=%s\n", deparray(srcname), objfile(srcname)
+ append = 0
+ for(f in imp){
+ if(f == srcname) {
+ continue
+ }
+ printf "include build/%s.deps.mk\n", f
+ append = 1
+ }
+ if(append) {
+ printf "%s+= $(sort ", da
+ for(f in imp){
+ printf " $(%s)", deparray(f)
+ }
+ printf ")\n"
+ }
+ printf "\nendif\n"
+}
diff --git a/scripts/link b/scripts/link
@@ -0,0 +1,2 @@
+#!/bin/sh -xe
+exec gcc -static "$@"
diff --git a/simplelink.mk b/simplelink.mk
@@ -0,0 +1,33 @@
+SRC_DIR ?= src
+BUILD_DIR ?= build
+SCRIPTS_DIR ?= scripts
+
+all_executables: $(patsubst %,$(BUILD_DIR)/%,$(executables))
+.PHONY: all_executables
+
+define simplelink =
+include $$(BUILD_DIR)/$(1)_main.c.deps.mk
+$$(BUILD_DIR)/$(1): $$(LINKDEP_$(1)_main__c) $$(SCRIPTS_DIR)/link $$(BUILD_DIR)/$(1)_main.c.deps.mk
+ $$(SCRIPTS_DIR)/link -o '$$@' $$(LINKDEP_$(1)_main__c)
+endef
+$(foreach var,$(executables),$(eval $(call simplelink,$(var))))
+
+## pattern rules:
+
+# preprocess C sources
+$(BUILD_DIR)/%.c.i: $(SRC_DIR)/%.c $(SCRIPTS_DIR)/cc $(BUILD_DIR)/.exists
+ $(SCRIPTS_DIR)/cc -E -C -o '$@' '$(SRC_DIR)/$*.c'
+
+# compile preprocessed C sources
+$(BUILD_DIR)/%.o: $(BUILD_DIR)/%.c.i $(SCRIPTS_DIR)/cc
+ $(SCRIPTS_DIR)/cc -fpreprocessed -c -o '$@' '$(BUILD_DIR)/$*.c.i'
+
+# extract dependencies from preprocessed sources
+$(BUILD_DIR)/%.c.deps.mk: $(BUILD_DIR)/%.c.i $(SCRIPTS_DIR)/codedeps.awk
+ awk -v srcname='$*.c' -v target='$(BUILD_DIR)/$*.c.i' -f $(SCRIPTS_DIR)/codedeps.awk '$(BUILD_DIR)/$*.c.i' >'$@.new'
+ mv '$@.new' '$@'
+
+# create directory if missing
+%/.exists:
+ mkdir -p '$*'
+ touch '$@'
diff --git a/src/hello_main.c b/src/hello_main.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+int main(int argc, char const *const *argv)
+{
+ if(printf("Hello %s!\n", "world") < 0) {
+ perror("error printing string");
+ return 111;
+ }
+ return 0;
+}