~emersion/mrsh-dev

Add configure script and Makefile v3 PROPOSED

Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~emersion/mrsh-dev/%3C20190715142441.28493-1-sir%40cmpwn.com%3E/mbox | git am -3
Learn more about email & git

[PATCH v3] Add configure script and Makefile Export this patch

The configure script is POSIX sh and the Makefile is POSIX make.
---
This removes the % rules, but as a consequence moves the list of source
files into the configure script and generates rules for them. This also
no longer supports out of tree builds, in order to take advantage of
POSIX inference rules.

 .gitignore             |   4 +
 Makefile               |  88 +++++++++++++
 configure              | 280 +++++++++++++++++++++++++++++++++++++++++
 mkpc                   |  12 ++
 test/conformance/if.sh |  16 +--
 test/harness.sh        |   6 +-
 test/meson.build       |   2 +-
 test/pipeline.sh       |   6 +-
 8 files changed, 399 insertions(+), 15 deletions(-)
 create mode 100644 Makefile
 create mode 100755 configure
 create mode 100755 mkpc
 mode change 100644 => 100755 test/harness.sh

diff --git a/.gitignore b/.gitignore
index 4c07ad0..32fe6d5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,3 +53,7 @@ dkms.conf
 
 /build
 /build-*
+
+.build
+highlight
+mrsh
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..5243c48
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,88 @@
+.POSIX:
+.SUFFIXES:
+OUTDIR=.build
+include $(OUTDIR)/config.mk
+
+INCLUDE=-Iinclude
+
+public_includes=\
+		include/mrsh/arithm.h \
+		include/mrsh/array.h \
+		include/mrsh/ast.h \
+		include/mrsh/buffer.h \
+		include/mrsh/builtin.h \
+		include/mrsh/entry.h \
+		include/mrsh/getopt.h \
+		include/mrsh/hashtable.h \
+		include/mrsh/parser.h \
+		include/mrsh/shell.h
+
+tests=\
+		test/conformance/if.sh \
+		test/case.sh \
+		test/command.sh \
+		test/for.sh \
+		test/function.sh \
+		test/loop.sh \
+		test/pipeline.sh \
+		test/subshell.sh \
+		test/syntax.sh \
+		test/ulimit.sh \
+		test/word.sh
+
+include $(OUTDIR)/cppcache
+
+.SUFFIXES: .c .o
+
+.c.o:
+	@mkdir -p $$(dirname "$@")
+	@printf 'CC\t$@\n'
+	@touch $(OUTDIR)/cppcache
+	@grep $< $(OUTDIR)/cppcache >/dev/null || \
+		$(CPP) $(INCLUDE) -MM -MT $@ $< >> $(OUTDIR)/cppcache
+	@$(CC) -c $(CFLAGS) $(INCLUDE) -o $@ $<
+
+$(OUTDIR)/libmrsh.a: $(libmrsh_objects)
+	@printf 'AR\t$@\n'
+	@$(AR) -csr $@ $(libmrsh_objects)
+
+libmrsh.so.$(SOVERSION): $(OUTDIR)/libmrsh.a
+	@printf 'LD\t$@\n'
+	@$(CC) -shared $(LDFLAGS) -o $@ $<
+
+$(OUTDIR)/mrsh.pc:
+	@printf 'MKPC\t$@\n'
+	@PREFIX=$(PREFIX) ./mkpc $@
+
+mrsh: $(OUTDIR)/libmrsh.a $(mrsh_objects)
+	@printf 'CCLD\t$@\n'
+	@$(CC) -o $@ $(LIBS) $(mrsh_objects) -L$(OUTDIR) -lmrsh
+
+highlight: $(OUTDIR)/libmrsh.a $(highlight_objects)
+	@printf 'CCLD\t$@\n'
+	@$(CC) -o $@ $(LIBS) $(highlight_objects) -L$(OUTDIR) -lmrsh
+
+check: mrsh $(tests)
+	@for t in $(tests); do \
+		printf '%-30s... ' "$$t" && \
+		MRSH=./mrsh REF_SH=$${REF_SH:-sh} ./test/harness.sh $$t >/dev/null && \
+		echo OK || echo FAIL; \
+	done
+
+install: mrsh libmrsh.so.$(SOVERSION) $(OUTDIR)/mrsh.pc
+	mkdir -p $(BINDIR) $(LIBDIR) $(INCDIR)/mrsh $(PCDIR)
+	install -m755 mrsh $(BINDIR)/mrsh
+	install -m755 libmrsh.so.$(SOVERSION) $(LIBDIR)/libmrsh.so.$(SOVERSION)
+	for inc in $(public_includes); do \
+		install -m644 $$inc $(INCDIR)/mrsh/$$(basename $$inc); \
+	done
+	install -m644 $(OUTDIR)/mrsh.pc $(PCDIR)/mrsh.pc
+
+clean:
+	rm -rf \
+		$(libmrsh_objects) \
+		$(mrsh_objects) \
+		$(highlight_objects) \
+		mrsh higlight libmrsh.so.$(SOVERSION) $(OUTDIR)/mrsh.pc
+
+.PHONY: all install clean check
diff --git a/configure b/configure
new file mode 100755
index 0000000..5b45848
--- /dev/null
+++ b/configure
@@ -0,0 +1,280 @@
+#!/bin/sh -e
+SOVERSION=0.0.0
+
+pkg_config=${PKG_CONFIG:-pkg-config}
+outdir=${OUTDIR:-.build}
+srcdir=${SRCDIR:-$(dirname "$0")}
+CC=${CC:-cc}
+LIBS=
+
+use_readline=-1
+readline=readline
+
+for arg
+do
+	case "$arg" in
+		--prefix=*)
+			PREFIX=${arg#*=}
+			;;
+		--without-readline)
+			use_readline=0
+			;;
+		--with-readline=*)
+			use_readline=1
+			readline=${arg#*=}
+			;;
+	esac
+done
+
+libmrsh() {
+	genrules libmrsh \
+		'arithm.c' \
+		'array.c' \
+		'ast_print.c' \
+		'ast.c' \
+		'buffer.c' \
+		'builtin/alias.c' \
+		'builtin/bg.c' \
+		'builtin/break.c' \
+		'builtin/builtin.c' \
+		'builtin/cd.c' \
+		'builtin/colon.c' \
+		'builtin/command.c' \
+		'builtin/dot.c' \
+		'builtin/eval.c' \
+		'builtin/exit.c' \
+		'builtin/export.c' \
+		'builtin/false.c' \
+		'builtin/fg.c' \
+		'builtin/getopts.c' \
+		'builtin/pwd.c' \
+		'builtin/read.c' \
+		'builtin/set.c' \
+		'builtin/shift.c' \
+		'builtin/times.c' \
+		'builtin/true.c' \
+		'builtin/type.c' \
+		'builtin/ulimit.c' \
+		'builtin/umask.c' \
+		'builtin/unalias.c' \
+		'builtin/unset.c' \
+		'builtin/unspecified.c' \
+		'builtin/wait.c' \
+		'getopt.c' \
+		'hashtable.c' \
+		'parser/arithm.c' \
+		'parser/parser.c' \
+		'parser/program.c' \
+		'parser/word.c' \
+		'shell/arithm.c' \
+		'shell/entry.c' \
+		'shell/job.c' \
+		'shell/path.c' \
+		'shell/process.c' \
+		'shell/redir.c' \
+		'shell/shell.c' \
+		'shell/task/pipeline.c' \
+		'shell/task/simple_command.c' \
+		'shell/task/task.c' \
+		'shell/task/word.c' \
+		'shell/word.c'
+}
+
+mrsh() {
+	if [ $use_readline -eq 1 ]
+	then
+		genrules mrsh \
+			'main.c' \
+			'frontend/readline.c'
+	else
+		genrules mrsh \
+			'main.c' \
+			'frontend/basic.c'
+	fi
+}
+
+highlight() {
+	genrules highlight highlight.c
+}
+
+genrules() {
+	target="$1"
+	shift
+	printf '# Begin generated rules for %s\n' "$target"
+	for file in "$@"
+	do
+		file="${file%.*}"
+		printf '%s.o: %s.c\n' "$file" "$file"
+	done
+	printf '%s_objects=\\\n' "$target"
+	n=0
+	for file in "$@"
+	do
+		file="${file%.*}"
+		n=$((n+1))
+		if [ $n -eq $# ]
+		then
+			printf '\t%s.o\n' "$file"
+		else
+			printf '\t%s.o \\\n' "$file"
+		fi
+	done
+	printf '# End generated rules for %s\n' "$target"
+}
+
+append_cflags() {
+	for flag
+	do
+		CFLAGS="$(printf '%s \\\n\t%s' "$CFLAGS" "$flag")"
+	done
+}
+
+append_ldflags() {
+	for flag
+	do
+		LDFLAGS="$(printf '%s \\\n\t%s' "$LDFLAGS" "$flag")"
+	done
+}
+
+append_libs() {
+	for flag
+	do
+		LIBS="$(printf '%s \\\n\t%s' "$LIBS" "$flag")"
+	done
+}
+
+test_cflags() {
+	[ ! -e "$outdir"/check.c ] && cat <<-EOF > "$outdir"/check.c
+	int main(void) { return 0; }
+	EOF
+	if $CC "$@" -o /dev/null "$outdir"/check.c >/dev/null 2>&1
+	then
+		append_cflags "$@"
+	else
+		return 1
+	fi
+}
+
+test_ldflags() {
+	[ ! -e "$outdir"/check.c ] && cat <<-EOF > "$outdir"/check.c
+	int main(void) { return 0; }
+	EOF
+	if $CC "$@" -o /dev/null "$outdir"/check.c >/dev/null 2>&1
+	then
+		append_ldflags "$@"
+	else
+		return 1
+	fi
+}
+
+mkdir -p $outdir
+
+for flag in \
+	-g -std=c99 -pedantic -Werror -Wundef -Wlogical-op \
+	-Wmissing-include-dirs -Wold-style-definition -Wpointer-arith -Winit-self \
+	-Wfloat-equal -Wstrict-prototypes -Wredundant-decls \
+	-Wimplicit-fallthrough=2 -Wendif-labels -Wstrict-aliasing=2 -Woverflow \
+	-Wformat=2 -Wno-missing-braces -Wno-missing-field-initializers \
+	-Wno-unused-parameter
+do
+	printf "Checking for $flag... "
+	if test_cflags "$flag"
+	then
+		echo yes
+	else
+		echo no
+	fi
+done
+
+for flag in -fPIC -Wl,--no-undefined -Wl,--as-needed
+do
+	test_ldflags "$flag"
+done
+
+soname=libmrsh.so.$(echo "$SOVERSION" | cut -d. -f1)
+printf "Checking for specifying soname for shared lib... "
+if ! \
+	test_ldflags -Wl,-soname,$soname || \
+	test_ldflags -Wl,-install_name,$soname
+then
+	echo no
+	echo "Unable to specify soname (is $(uname) supported?)" >&2
+	exit 1
+else
+	echo yes
+fi
+
+printf "Checking for exported symbol restrictions... "
+if ! \
+	test_ldflags -Wl,--version-script="libmrsh.gnu.sym" || \
+	test_ldflags -Wl,-exported_symbols_list,"libmrsh.darwin.sym"
+then
+	echo no
+	echo "Unable to specify exported symbols (is $(uname) supported?)" >&2
+	exit 1
+else
+	echo yes
+fi
+
+if [ $use_readline -eq -1 ]
+then
+	printf "Checking for readline... "
+	if $pkg_config readline
+	then
+		readline=readline
+		use_readline=1
+		append_cflags -DHAVE_READLINE
+		echo yes
+	else
+		echo no
+	fi
+fi
+if [ $use_readline -eq -1 ]
+then
+	printf "Checking for libedit... "
+	if $pkg_config libedit
+	then
+		echo yes
+		readline=libedit
+		use_readline=1
+		append_cflags -DHAVE_EDITLINE
+	else
+		echo no
+	fi
+fi
+
+if [ $use_readline -eq 1 ]
+then
+	append_cflags $($pkg_config --cflags $readline)
+	append_libs $($pkg_config --libs $readline)
+	if [ "$readline" = "readline" ]
+	then
+		# Undo GNU_SOURCE
+		append_cflags -U_GNU_SOURCE
+	fi
+fi
+
+printf "Creating $outdir/config.mk... "
+cat <<EOF > "$outdir"/config.mk
+SOVERSION=$SOVERSION
+CC=$CC
+PREFIX=${PREFIX:-/usr/local}
+_INSTDIR=\$(DESTDIR)\$(PREFIX)
+BINDIR?=${BINDIR:-\$(_INSTDIR)/bin}
+LIBDIR?=${LIBDIR:-\$(_INSTDIR)/lib}
+INCDIR?=${INCDIR:-\$(_INSTDIR)/include}
+MANDIR?=${MANDIR:-\$(_INSTDIR)/share/man}
+PCDIR?=${PCDIR:-\$(_INSTDIR)/lib/pkgconfig}
+CFLAGS=${CFLAGS}
+LDFLAGS=${LDFLAGS}
+LIBS=${LIBS}
+SRCDIR=${srcdir}
+
+all: mrsh highlight libmrsh.so.\$(SOVERSION) \$(OUTDIR)/mrsh.pc
+EOF
+libmrsh >>"$outdir"/config.mk
+mrsh >>"$outdir"/config.mk
+highlight >>"$outdir"/config.mk
+echo done
+
+touch $outdir/cppcache
diff --git a/mkpc b/mkpc
new file mode 100755
index 0000000..9916e9b
--- /dev/null
+++ b/mkpc
@@ -0,0 +1,12 @@
+#!/bin/sh
+cat <<EOF > $1
+prefix=$PREFIX
+libdir=\${prefix}/lib
+includedir=\${prefix}/include
+
+Name: mrsh
+Description: POSIX shell library
+Version: 0.0.0
+Libs: -L\${libdir} -lmrsh
+Cflags: -I\${includedir}
+EOF
diff --git a/test/conformance/if.sh b/test/conformance/if.sh
index 258fbd7..0be4160 100644
--- a/test/conformance/if.sh
+++ b/test/conformance/if.sh
@@ -7,20 +7,20 @@
 # pass
 # pass
 
-echo >&2 "-> if..fi with true condition"
+echo "-> if..fi with true condition"
 if true
 then
 	echo pass
 fi
 
-echo >&2 "-> if..fi with false condition"
+echo "-> if..fi with false condition"
 if false
 then
 	echo >&2 "fail: This branch should not have run" && exit 1
 fi
 echo pass
 
-echo >&2 "-> if..else..fi with true condition"
+echo "-> if..else..fi with true condition"
 if true
 then
 	echo pass
@@ -28,7 +28,7 @@ else
 	echo >&2 "fail: This branch should not have run" && exit 1
 fi
 
-echo >&2 "-> if..else..fi with false condition"
+echo "-> if..else..fi with false condition"
 if false
 then
 	echo >&2 "fail: This branch should not have run" && exit 1
@@ -36,7 +36,7 @@ else
 	echo pass
 fi
 
-echo >&2 "-> if..else..fi with true condition"
+echo "-> if..else..fi with true condition"
 if true
 then
 	echo pass
@@ -44,7 +44,7 @@ else
 	echo >&2 "fail: This branch should not have run" && exit 1
 fi
 
-echo >&2 "-> if..else..elif..fi with false condition"
+echo "-> if..else..elif..fi with false condition"
 if false
 then
 	echo >&2 "fail: This branch should not have run" && exit 1
@@ -55,7 +55,7 @@ else
 	echo >&2 "fail: This branch should not have run" && exit 1
 fi
 
-echo >&2 "-> test exit status"
+echo "-> test exit status"
 if true
 then
 	( exit 10 )
@@ -71,7 +71,7 @@ else
 fi
 [ $# -eq 20 ] || { echo >&2 "fail: Expected status code = 20" && exit 1; }
 
-echo >&2 "-> test alternate syntax"
+echo "-> test alternate syntax"
 # These tests are only expected to parse, they do not make assertions
 if true; then true; fi
 if true; then true; else true; fi
diff --git a/test/harness.sh b/test/harness.sh
old mode 100644
new mode 100755
index d05a744..885aa74
--- a/test/harness.sh
+++ b/test/harness.sh
@@ -1,11 +1,11 @@
 #!/bin/sh
 dir=$(dirname "$0")
-testcase="$dir/$1"
+testcase="$1"
 
-echo >&2 "Running with mrsh"
+echo "Running with mrsh"
 mrsh_out=$("$MRSH" "$testcase")
 mrsh_ret=$?
-echo >&2 "Running with reference shell"
+echo "Running with reference shell"
 ref_out=$("$REF_SH" "$testcase")
 ref_ret=$?
 if [ $mrsh_ret -ne $ref_ret ] || [ "$mrsh_out" != "$ref_out" ]
diff --git a/test/meson.build b/test/meson.build
index 1df5daa..7e18c0d 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -19,7 +19,7 @@ test_files = [
 
 foreach test_file : test_files
 	test(
-		test_file,
+		join_paths(meson.current_source_dir(), test_file),
 		harness,
 		env: [
 			'MRSH=@0@'.format(mrsh_exe.full_path()),
diff --git a/test/pipeline.sh b/test/pipeline.sh
index 3d60740..7c2d449 100644
--- a/test/pipeline.sh
+++ b/test/pipeline.sh
@@ -1,12 +1,12 @@
 #!/bin/sh
 
-echo >&2 "Pipeline with 1 command"
+echo "Pipeline with 1 command"
 echo "a b c d"
 
-echo >&2 "Pipeline with 2 commands"
+echo "Pipeline with 2 commands"
 echo "a b c d" | sed s/b/B/
 
-echo >&2 "Pipeline with 3 commands"
+echo "Pipeline with 3 commands"
 echo "a b c d" | sed s/b/B/ | sed s/c/C/
 
 echo >&2 "Pipeline with bang"
-- 
2.22.0
View this thread in the archives