~emersion/mrsh-dev

Add configure script and Makefile v4 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/%3C20190717201216.20126-1-sir%40cmpwn.com%3E/mbox | git am -3
Learn more about email & git

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

The configure script is POSIX sh and the Makefile is POSIX make.
---
This version fixes a typo pointed out by Stephen Gregoratto

 .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..d57e8b5
--- /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 highlight 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

Re: [PATCH v4] Add configure script and Makefile Export this patch

This updated diff still doesn't fix the build errors I reported on
OpenBSD 6.5. It looks like some warnings are not available/different
on clang:

CC      arithm.o
error: unknown warning option '-Wlogical-op'; did you mean '-Wlong-long'? [-Werror,-Wunknown-warning-option]
error: unknown warning option '-Wimplicit-fallthrough=2'; did you mean '-Wimplicit-fallthrough'?
      [-Werror,-Wunknown-warning-option]
*** Error 1 in /home/liquid/gits/mrsh (Makefile:43 'arithm.o': @cc -c -g  -std=c99  -pedantic  -Werror  -Wundef
-Wlogical-op  -Wmissing-inc...)
Compiling with gcc 8 from ports got me to the end, but not without a
couple warnings:

LD      libmrsh.so.0.0.0
Using $< in a non-suffix rule context is a GNUmake idiom (Makefile:51)

This can be fixed with the following:

diff --git a/Makefile b/Makefile
index d57e8b5..ebe9899 100644
--- a/Makefile
+++ b/Makefile
@@ -48,7 +48,7 @@ $(OUTDIR)/libmrsh.a: $(libmrsh_objects)

 libmrsh.so.$(SOVERSION): $(OUTDIR)/libmrsh.a
        @printf 'LD\t$@\n'
-       @$(CC) -shared $(LDFLAGS) -o $@ $<
+       @$(CC) -shared $(LDFLAGS) -o $@ $(OUTDIR)/libmrsh.a

 $(OUTDIR)/mrsh.pc:
        @printf 'MKPC\t$@\n'

-- 
Stephen Gregoratto
PGP: 3FC6 3D0E 2801 C348 1C44 2D34 A80C 0F8E 8BAB EC8B
View this thread in the archives