From 84ecadc9280f728df7e84e2bd1745d6148953605 Mon Sep 17 00:00:00 2001 From: John Bartholomew Date: Sun, 8 Feb 2026 20:11:59 +0000 Subject: [PATCH 1/4] rewrite the plain Makefile, add GoogleTest support In particular: * The (system) GoogleTest library is found using pkg-config. * Test binaries are built. * Object files are put in a .makebuild/ directory to keep them separate from the code tree (for cleanliness) * Dependencies are discovered during normal compilation instead of using a separate depends step. * Variables are cleaned up a bit. * The use of the `od` command from the environment is dropped, instead the Makefile builds and uses the to_c_array program (which is how the CMakeLists and Bazel builds already work) * Instead of grep|cut|sed to extract the version number, a single `sed` command is used. * The test binaries have their rpath set to $ORIGIN so that they can find the local libjsonnet.so where they are without LD_LIBRARY_PATH shenanigans. * tests.sh now executes the GoogleTest tests as well --- .gitignore | 14 ++- Makefile | 294 +++++++++++++++++++++++++++-------------------------- tests.sh | 9 +- 3 files changed, 166 insertions(+), 151 deletions(-) diff --git a/.gitignore b/.gitignore index d52ae7b9d..747e61d28 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ **/*.a **/*.dylib *.dSYM +.makebuild/ jsonnet jsonnetfmt @@ -17,17 +18,24 @@ libjsonnet.so libjsonnet.so.* libjsonnet++.so libjsonnet++.so.* -libjsonnet_test_file -libjsonnet_test_snippet -libjsonnet_test_locale **/core.* **/vgcore **/vgcore.* core/std.jsonnet.h +stdlib/to_c_array Makefile.depend Makefile.depend.bak bazel-* +libjsonnet_test_file +libjsonnet_test_snippet +libjsonnet_test_locale +libjsonnet_test +libjsonnet++_test +unicode_test +lexer_test +parser_test + **/*.tfstate **/*.tfstate.backup diff --git a/Makefile b/Makefile index 1ce462a7b..26f530e75 100644 --- a/Makefile +++ b/Makefile @@ -19,40 +19,69 @@ # C/C++ compiler; to use Clang, build with `make CC=clang CXX=clang++` CXX ?= g++ CC ?= gcc +# coreutils `install` command +INSTALL ?= install +# The `help2man` command +HELP2MAN ?= help2man -CP ?= cp -OD ?= od - -OPT ?= -O3 - +# Directories to place installed files. PREFIX ?= /usr/local +MAN1_DIR ?= man/man1 -CXXFLAGS ?= -g $(OPT) -Wall -Wextra -Woverloaded-virtual -pedantic -std=c++17 -fPIC -CXXFLAGS += -Iinclude -Ithird_party/md5 -Ithird_party/json -Ithird_party/rapidyaml/ -CFLAGS ?= -g $(OPT) -Wall -Wextra -pedantic -std=c99 -fPIC -CFLAGS += -Iinclude -MAKEDEPENDFLAGS += -Iinclude -Ithird_party/md5 -Ithird_party/json +# Default optimisation level (override by passing OPT=... in the make invocation) +OPT ?= -O3 +# Default flags (can be overriden by passing CXXFLAGS=... in the make invocation) +CXXFLAGS ?= -g $(OPT) -Wall -Wextra -Woverloaded-virtual -pedantic -fPIC +# Required flags (including -std=c++17) +CXXFLAGS += -std=c++17 -Iinclude -Ithird_party/md5 -Ithird_party/json -Ithird_party/rapidyaml/ +# Default C compilation flags (can be overridden by passing CFLAGS=... in the make invocation) +CFLAGS ?= -g $(OPT) -Wall -Wextra -pedantic -fPIC +# Required C compilation flags (including -std=c99) +CFLAGS += -std=c99 -Iinclude +# Default flags for linking binaries LDFLAGS ?= - - +# Default flags for linking .so shared objects SHARED_LDFLAGS ?= -shared -VERSION := $(shell grep '\#define.*LIB_JSONNET_VERSION' include/libjsonnet.h | head -n 1 | cut -f 2 -d '"' | sed 's/^v//g' ) -SOVERSION = 0 +### +# GoogleTest library, from the system. +# -# Define the help2man command with appropriate options -HELP2MAN ?= help2man +GTEST_PKG := gtest_main -MAN1_DIR ?= man/man1 +ifeq ($(shell pkg-config --exists $(GTEST_PKG) && echo 0),0) + GTEST_CXXFLAGS := $(shell pkg-config --cflags $(GTEST_PKG)) + GTEST_LDFLAGS := $(shell pkg-config --libs $(GTEST_PKG)) +else + $(warning "pkg-config could not find $(GTEST_PKG). Tests will not be buildable.") +endif + +# --- End Google Test Integration --- ################################################################################ # End of user-servicable parts ################################################################################ -RAPIDYAML_SRC = \ - third_party/rapidyaml/rapidyaml.cpp +# Disable all GNU Make builtin rules, we want to specify our own. +.SUFFIXES: + +# Single sed invocation that finds and extracts the version from the libjsonnet.h header. +# Hash and Dollar characters use hex escapes to avoid angering the Makefile interpreter. +EXTRACT_VERSION_SED := /^[ \t]*\x23[ \t]*define[ \t]+LIB_JSONNET_VERSION[ \t]+["]v([0-9.]+(-?[a-z][a-z0-9]*)?)["][ \t]*\x24/ { s//\1/p; q; } -LIB_SRC = \ +# Extract the library version from libjsonnet.h. +VERSION := $(shell sed -nE '$(EXTRACT_VERSION_SED)' include/libjsonnet.h) +SOVERSION := 0 + +ifeq ($(shell uname -s),Darwin) + SONAME_FLAG := -install_name + TEST_RPATH_FLAG := -Wl,-rpath,'@executable_path' +else + SONAME_FLAG := -soname + TEST_RPATH_FLAG := -Wl,-rpath,'$$ORIGIN' +endif + +LIB_SRC := \ core/desugarer.cpp \ core/formatter.cpp \ core/lexer.cpp \ @@ -64,20 +93,27 @@ LIB_SRC = \ core/string_utils.cpp \ core/vm.cpp \ third_party/md5/md5.cpp \ - $(RAPIDYAML_SRC) + third_party/rapidyaml/rapidyaml.cpp -LIB_OBJ = $(LIB_SRC:.cpp=.o) +LIB_OBJ := $(addprefix .makebuild/,$(addsuffix .o,$(LIB_SRC))) -LIB_CPP_SRC = \ +LIB_CPP_SRC := \ cpp/libjsonnet++.cpp -LIB_CPP_OBJ = $(LIB_OBJ) $(LIB_CPP_SRC:.cpp=.o) +LIB_CPP_OBJ := $(LIB_OBJ) $(addprefix .makebuild/,$(addsuffix .o,$(LIB_CPP_SRC))) + +BINS_SRC := \ + cmd/utils.cpp \ + cmd/jsonnetfmt.cpp \ + cmd/jsonnet.cpp -BINS = \ +BINS := \ jsonnet \ jsonnetfmt -LIBS = \ +MAN_PAGES := $(addprefix $(MAN1_DIR)/,$(addsuffix .1,$(BINS))) + +LIBS := \ libjsonnet.so \ libjsonnet.so.$(SOVERSION) \ libjsonnet.so.$(VERSION) \ @@ -85,154 +121,120 @@ LIBS = \ libjsonnet++.so.$(SOVERSION) \ libjsonnet++.so.$(VERSION) \ -ALL = \ - libjsonnet_test_snippet \ - libjsonnet_test_file \ - $(BINS) \ - $(LIBS) \ - $(LIB_OBJ) \ - $(LIB_CPP_OBJ) - -# public headers -INCS = \ +PUBLIC_HEADERS := \ include/libjsonnet.h \ include/libjsonnet_fmt.h \ include/libjsonnet++.h -ALL_HEADERS = \ - core/ast.h \ - core/desugarer.h \ - core/formatter.h \ - core/lexer.h \ - core/parser.h \ - core/state.h \ - core/static_analysis.h \ - core/static_error.h \ - core/string_utils.h \ - core/vm.h \ - core/std.jsonnet.h \ - third_party/md5/md5.h \ - third_party/json/json.hpp \ - third_party/rapidyaml/rapidyaml-0.10.0.hpp \ - $(INCS) - - -default: $(LIBS) $(BINS) - -bins: jsonnet jsonnetfmt -libs: libjsonnet.so libjsonnet++.so +TEST_SRC := \ + cpp/libjsonnet_test_locale.cpp \ + cpp/libjsonnet++_test.cpp \ + core/libjsonnet_test.cpp \ + core/lexer_test.cpp \ + core/unicode_test.cpp \ + core/parser_test.cpp \ + core/libjsonnet_test_file.c \ + core/libjsonnet_test_snippet.c -SONAME = -soname -ifeq ($(shell uname -s),Darwin) - SONAME = -install_name -endif +BIN_OBJ := $(addprefix .makebuild/,$(addsuffix .o,$(BINS_SRC) $(TEST_SRC))) +TEST_BINS := $(basename $(notdir $(TEST_SRC))) -default: jsonnet jsonnetfmt man +DEPS_FILES := $(addprefix .makebuild/,$(addsuffix .d,$(LIB_SRC) $(LIB_CPP_SRC) $(BINS_SRC) $(TEST_SRC))) +# Intermediate build output directories. +BUILD_DIRS := $(sort $(dir $(DEPS_FILES)) .makebuild/stdlib/) -install: bins libs man - mkdir -p $(DESTDIR)$(PREFIX)/bin - cp $(BINS) $(DESTDIR)$(PREFIX)/bin/ - mkdir -p $(DESTDIR)$(PREFIX)/lib - cp $(LIBS) $(DESTDIR)$(PREFIX)/lib/ - mkdir -p $(DESTDIR)$(PREFIX)/include - cp $(INCS) $(DESTDIR)$(PREFIX)/include/ - mkdir -p $(DESTDIR)$(PREFIX)/share/$(MAN1_DIR) - install -Dm 644 $(addprefix $(MAN1_DIR)/, $(BINS:=.1)) $(DESTDIR)$(PREFIX)/share/$(MAN1_DIR)/ +################################################################################ +# Targets / Build rules +################################################################################ +ALL := $(LIBS) $(BINS) $(MAN_PAGES) $(TEST_BINS) +.PHONY: default bins libs man all install dist clean +default: $(LIBS) $(BINS) +bins: $(BINS) +libs: $(LIBS) +man: $(MAN_PAGES) all: $(ALL) -test: jsonnet jsonnetfmt libjsonnet.so libjsonnet_test_snippet libjsonnet_test_file +test: bins libs $(TEST_BINS) ./tests.sh -reformat: - clang-format -i -style=file **/*.cpp **/*.h - -test-formatting: - clang-format -Werror --dry-run -style=file **/*.cpp **/*.h +dist: + @{ >&2 echo "The dist target is no longer supported, please don't use it." ; exit 1 ; } -MAKEDEPEND_SRCS = \ - cmd/jsonnet.cpp \ - cmd/jsonnetfmt.cpp \ - core/libjsonnet_test_snippet.c \ - core/libjsonnet_test_file.c +clean: + { \ + rm -df \ + $(BINS) $(LIBS) $(MAN_PAGES) $(TEST_BINS) \ + stdlib/to_c_array core/std.jsonnet.h \ + && rm -rf .makebuild ;\ + } -depend: core/std.jsonnet.h - rm -f Makefile.depend - for FILE in $(LIB_SRC) $(MAKEDEPEND_SRCS) ; do $(CXX) -MM $(CXXFLAGS) $$FILE -MT $$(dirname $$FILE)/$$(basename $$FILE .cpp).o >> Makefile.depend ; done +install: bins libs man + { \ + $(INSTALL) -Dm 644 -t $(DESTDIR)$(PREFIX)/bin/ $(BINS) ;\ + $(INSTALL) -Dm 644 -t $(DESTDIR)$(PREFIX)/lib/ $(LIBS) ;\ + $(INSTALL) -Dm 644 -t $(DESTDIR)$(PREFIX)/include/ $(PUBLIC_HEADERS) ;\ + $(INSTALL) -Dm 644 -t $(DESTDIR)$(PREFIX)/share/$(MAN1_DIR)/ $(MAN_PAGES) ;\ + } -core/desugarer.cpp: core/std.jsonnet.h +CC_DEPS_FLAGS = -MMD -MP -MF "$(addsuffix .d,$@)" -# Object files -%.o: %.cpp - $(CXX) -c $(CXXFLAGS) $< -o $@ +.makebuild/%.cpp.o: %.cpp + mkdir -p $(@D) && $(CXX) $(CC_DEPS_FLAGS) $(CXXFLAGS) -o $@ -c $< +.makebuild/%.c.o: %.c + mkdir -p $(@D) && $(CC) $(CC_DEPS_FLAGS) $(CFLAGS) -o $@ -c $< -# Target to generate the man page +%.so.$(SOVERSION): %.so.$(VERSION) + ln -sf $< $@ +%.so: %.so.$(SOVERSION) + ln -sf $< $@ -$(MAN1_DIR)/%.1: % | $(MAN1_DIR) +$(MAN_PAGES): $(MAN1_DIR)/%.1: % | $(MAN1_DIR) $(HELP2MAN) --no-info --output=$@ ./$< -man: $(addprefix $(MAN1_DIR)/, $(BINS:=.1)) - $(MAN1_DIR): mkdir -p $@ -# Commandline executable. -jsonnet: cmd/jsonnet.cpp cmd/utils.cpp $(LIB_OBJ) - $(CXX) $(CXXFLAGS) $(LDFLAGS) $< cmd/utils.cpp $(LIB_SRC:.cpp=.o) -o $@ +jsonnet: .makebuild/cmd/jsonnet.cpp.o .makebuild/cmd/utils.cpp.o $(LIB_OBJ) + $(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -# Commandline executable (reformatter). -jsonnetfmt: cmd/jsonnetfmt.cpp cmd/utils.cpp $(LIB_OBJ) - $(CXX) $(CXXFLAGS) $(LDFLAGS) $< cmd/utils.cpp $(LIB_SRC:.cpp=.o) -o $@ +jsonnetfmt: .makebuild/cmd/jsonnetfmt.cpp.o .makebuild/cmd/utils.cpp.o $(LIB_OBJ) + $(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -# C binding. libjsonnet.so.$(VERSION): $(LIB_OBJ) - $(CXX) $(LDFLAGS) $(LIB_OBJ) $(SHARED_LDFLAGS) -Wl,$(SONAME),libjsonnet.so.$(SOVERSION) -o $@ + $(CXX) $(LDFLAGS) $(LIB_OBJ) $(SHARED_LDFLAGS) -Wl,$(SONAME_FLAG),libjsonnet.so.$(SOVERSION) -o $@ libjsonnet++.so.$(VERSION): $(LIB_CPP_OBJ) - $(CXX) $(LDFLAGS) $(LIB_CPP_OBJ) $(SHARED_LDFLAGS) -Wl,$(SONAME),libjsonnet++.so.$(SOVERSION) -o $@ - -%.so.$(SOVERSION): %.so.$(VERSION) - ln -sf $< $@ + $(CXX) $(LDFLAGS) $(LIB_CPP_OBJ) $(SHARED_LDFLAGS) -Wl,$(SONAME_FLAG),libjsonnet++.so.$(SOVERSION) -o $@ -%.so: %.so.$(SOVERSION) - ln -sf $< $@ - -# Tests for C binding. -LIBJSONNET_TEST_SNIPPET_SRCS = \ - core/libjsonnet_test_snippet.c \ - libjsonnet.so \ - include/libjsonnet.h - -libjsonnet_test_snippet: $(LIBJSONNET_TEST_SNIPPET_SRCS) - $(CC) $(CFLAGS) $(LDFLAGS) $< -L. -ljsonnet -o $@ - -LIBJSONNET_TEST_FILE_SRCS = \ - core/libjsonnet_test_file.c \ - libjsonnet.so \ - include/libjsonnet.h - -libjsonnet_test_file: $(LIBJSONNET_TEST_FILE_SRCS) - $(CC) $(CFLAGS) $(LDFLAGS) $< -L. -ljsonnet -o $@ +# std.jsonnet.h is a generated file so the first build will fail if it isn't +# specified as an explicit dependency (after that, deps are known from compiler output) +core/desugarer.cpp: core/std.jsonnet.h # Encode standard library for embedding in C -core/%.jsonnet.h: stdlib/%.jsonnet - (($(OD) -v -Anone -t u1 $< \ - | tr " " "\n" \ - | grep -v "^$$" \ - | tr "\n" "," ) && echo "0") > $@ - echo >> $@ - - -RELEASE_FILE = jsonnet-bin.tar.gz - -$(RELEASE_FILE): bins - tar czf $@ $(BINS) - -dist: $(RELEASE_FILE) - -clean: - rm -rvf */*~ *~ .*~ */.*.swp .*.swp $(ALL) *.o core/*.jsonnet.h Makefile.depend *.so.* build jsonnet.egg-info $(RELEASE_FILE) man - --include Makefile.depend - -.PHONY: default all depend clean reformat test test-formatting +.makebuild/stdlib/to_c_array: stdlib/to_c_array.cpp + mkdir -p $(@D) && $(CXX) $(CXXFLAGS) -o "$@" $^ + +core/%.jsonnet.h: stdlib/%.jsonnet .makebuild/stdlib/to_c_array + .makebuild/stdlib/to_c_array "$<" "$@" + +# C++ lib tests (links to libjsonnet++.so) +libjsonnet_test_locale libjsonnet++_test: %: .makebuild/cpp/%.cpp.o libjsonnet++.so + $(CXX) $(CXXFLAGS) $(GTEST_CXXFLAGS) -o $@ $^ $(LDFLAGS) $(GTEST_LDFLAGS) $(TEST_RPATH_FLAG) + +# Plain-C tests (link to libjsonnet.so); don't use GoogleTest (which is C++ only) +libjsonnet_test_file libjsonnet_test_snippet: %: .makebuild/core/%.c.o libjsonnet.so + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(TEST_RPATH_FLAG) +# C++ tests of the C API (link to libjsonnet.so) +libjsonnet_test: %: .makebuild/core/%.cpp.o libjsonnet.so + $(CXX) $(CXXFLAGS) $(GTEST_CXXFLAGS) -o $@ $^ $(LDFLAGS) $(GTEST_LDFLAGS) $(TEST_RPATH_FLAG) + +# Core component unit tests (narrow deps) +lexer_test: %: .makebuild/core/%.cpp.o .makebuild/core/lexer.cpp.o + $(CXX) $(CXXFLAGS) $(GTEST_CXXFLAGS) -o $@ $^ $(LDFLAGS) $(GTEST_LDFLAGS) +unicode_test: %: .makebuild/core/%.cpp.o + $(CXX) $(CXXFLAGS) $(GTEST_CXXFLAGS) -o $@ $^ $(LDFLAGS) $(GTEST_LDFLAGS) +parser_test: %: .makebuild/core/%.cpp.o .makebuild/core/parser.cpp.o .makebuild/core/lexer.cpp.o + $(CXX) $(CXXFLAGS) $(GTEST_CXXFLAGS) -o $@ $^ $(LDFLAGS) $(GTEST_LDFLAGS) + +-include $(DEPS_FILES) diff --git a/tests.sh b/tests.sh index 235e9ef39..e5e54b4dc 100755 --- a/tests.sh +++ b/tests.sh @@ -8,10 +8,15 @@ printf "snippet: " if [ -z "$DISABLE_LIB_TESTS" ]; then printf 'libjsonnet_test_snippet: ' - LD_LIBRARY_PATH=. ./libjsonnet_test_snippet "${TEST_SNIPPET}" || FAIL=TRUE + ./libjsonnet_test_snippet "${TEST_SNIPPET}" || FAIL=TRUE printf 'libjsonnet_test_file: ' - LD_LIBRARY_PATH=. ./libjsonnet_test_file "test_suite/object.jsonnet" || FAIL=TRUE + ./libjsonnet_test_file "test_suite/object.jsonnet" || FAIL=TRUE fi +./unicode_test || FAIL=TRUE +./lexer_test || FAIL=TRUE +./parser_test || FAIL=TRUE +./libjsonnet_test || FAIL=TRUE +./libjsonnet++_test || FAIL=TRUE examples/check.sh || FAIL=TRUE examples/terraform/check.sh || FAIL=TRUE test_cmd/run_cmd_tests.sh || FAIL=TRUE From f2b049e2e1d2663c221a8bb631686af9c779a2f5 Mon Sep 17 00:00:00 2001 From: John Bartholomew Date: Sun, 8 Feb 2026 21:36:24 +0000 Subject: [PATCH 2/4] plain Makefile: make GoogleTest optional Not everyone will have it installed; if it's missing then just skip those tests. Unless the user tells us to use it, in which case abort. Also, warn if it's missing, unless the user tells us _not_ to use it. --- Makefile | 83 +++++++++++++++++++++++++++++++++++++++++--------------- tests.sh | 11 ++++---- 2 files changed, 67 insertions(+), 27 deletions(-) diff --git a/Makefile b/Makefile index 26f530e75..6fb6b751d 100644 --- a/Makefile +++ b/Makefile @@ -49,11 +49,26 @@ SHARED_LDFLAGS ?= -shared GTEST_PKG := gtest_main -ifeq ($(shell pkg-config --exists $(GTEST_PKG) && echo 0),0) - GTEST_CXXFLAGS := $(shell pkg-config --cflags $(GTEST_PKG)) - GTEST_LDFLAGS := $(shell pkg-config --libs $(GTEST_PKG)) +GTEST_FOUND := $(shell pkg-config --exists '$(GTEST_PKG)' && echo yes || echo no) +ifeq ($(GTEST_FOUND),yes) +GTEST_CXXFLAGS := $(shell pkg-config --cflags '$(GTEST_PKG)') +GTEST_LDFLAGS := $(shell pkg-config --libs '$(GTEST_PKG)') +endif + +ifeq ($(origin GTEST_ENABLED),undefined) +GTEST_ENABLED := $(GTEST_FOUND) +ifeq ($(GTEST_ENABLED),no) +$(warning GoogleTest package was not found on the system, some tests will be skipped.) +endif +else ifeq ($(GTEST_ENABLED),$(GTEST_FOUND)) +# Desired state matches found state; we're fine. +else ifeq ($(GTEST_ENABLED),no) +# GoogleTest was explicitly disabled; that's fine. +else ifeq ($(GTEST_ENABLED),yes) +$(error GoogleTest was explicitly requested but is not found on the system.) +override GTEST_ENABLED := no else - $(warning "pkg-config could not find $(GTEST_PKG). Tests will not be buildable.") +$(error GTEST_ENABLED was set to some invalid value, it must be unset, 'yes', or 'no') endif # --- End Google Test Integration --- @@ -74,12 +89,16 @@ VERSION := $(shell sed -nE '$(EXTRACT_VERSION_SED)' include/libjsonnet.h) SOVERSION := 0 ifeq ($(shell uname -s),Darwin) - SONAME_FLAG := -install_name - TEST_RPATH_FLAG := -Wl,-rpath,'@executable_path' -else - SONAME_FLAG := -soname - TEST_RPATH_FLAG := -Wl,-rpath,'$$ORIGIN' -endif + +SONAME_FLAG := -install_name +TEST_RPATH_FLAG := -Wl,-rpath,'@executable_path' + +else # else assume Linux-like + +SONAME_FLAG := -soname +TEST_RPATH_FLAG := -Wl,-rpath,'$$ORIGIN' + +endif # platform switch LIB_SRC := \ core/desugarer.cpp \ @@ -126,28 +145,36 @@ PUBLIC_HEADERS := \ include/libjsonnet_fmt.h \ include/libjsonnet++.h -TEST_SRC := \ +PLAIN_TEST_SRC := \ + core/libjsonnet_test_file.c \ + core/libjsonnet_test_snippet.c +GTEST_TEST_SRC := \ cpp/libjsonnet_test_locale.cpp \ cpp/libjsonnet++_test.cpp \ core/libjsonnet_test.cpp \ core/lexer_test.cpp \ core/unicode_test.cpp \ - core/parser_test.cpp \ - core/libjsonnet_test_file.c \ - core/libjsonnet_test_snippet.c + core/parser_test.cpp -BIN_OBJ := $(addprefix .makebuild/,$(addsuffix .o,$(BINS_SRC) $(TEST_SRC))) -TEST_BINS := $(basename $(notdir $(TEST_SRC))) +PLAIN_TEST_BINS := $(basename $(notdir $(PLAIN_TEST_SRC))) +GTEST_TEST_BINS := $(basename $(notdir $(GTEST_TEST_SRC))) +ALL_TEST_BINS := $(PLAIN_TEST_BINS) $(GTEST_TEST_BINS) DEPS_FILES := $(addprefix .makebuild/,$(addsuffix .d,$(LIB_SRC) $(LIB_CPP_SRC) $(BINS_SRC) $(TEST_SRC))) # Intermediate build output directories. BUILD_DIRS := $(sort $(dir $(DEPS_FILES)) .makebuild/stdlib/) +ifeq ($(GTEST_ENABLED),yes) +ENABLED_TEST_BINS := $(ALL_TEST_BINS) +else +ENABLED_TEST_BINS := $(PLAIN_TEST_BINS) +endif + ################################################################################ # Targets / Build rules ################################################################################ -ALL := $(LIBS) $(BINS) $(MAN_PAGES) $(TEST_BINS) +ALL := $(LIBS) $(BINS) $(MAN_PAGES) $(ENABLED_TEST_BINS) .PHONY: default bins libs man all install dist clean default: $(LIBS) $(BINS) bins: $(BINS) @@ -155,7 +182,7 @@ libs: $(LIBS) man: $(MAN_PAGES) all: $(ALL) -test: bins libs $(TEST_BINS) +test: bins libs $(ENABLED_TEST_BINS) ./tests.sh dist: @@ -164,7 +191,7 @@ dist: clean: { \ rm -df \ - $(BINS) $(LIBS) $(MAN_PAGES) $(TEST_BINS) \ + $(BINS) $(LIBS) $(MAN_PAGES) $(ALL_TEST_BINS) \ stdlib/to_c_array core/std.jsonnet.h \ && rm -rf .makebuild ;\ } @@ -218,13 +245,20 @@ core/desugarer.cpp: core/std.jsonnet.h core/%.jsonnet.h: stdlib/%.jsonnet .makebuild/stdlib/to_c_array .makebuild/stdlib/to_c_array "$<" "$@" +# Plain-C tests (link to libjsonnet.so); don't use GoogleTest (which is C++ only) +libjsonnet_test_file libjsonnet_test_snippet: %: .makebuild/core/%.c.o libjsonnet.so + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(TEST_RPATH_FLAG) + +### +# Tests that use GoogleTest +# + +ifeq ($(GTEST_ENABLED),yes) + # C++ lib tests (links to libjsonnet++.so) libjsonnet_test_locale libjsonnet++_test: %: .makebuild/cpp/%.cpp.o libjsonnet++.so $(CXX) $(CXXFLAGS) $(GTEST_CXXFLAGS) -o $@ $^ $(LDFLAGS) $(GTEST_LDFLAGS) $(TEST_RPATH_FLAG) -# Plain-C tests (link to libjsonnet.so); don't use GoogleTest (which is C++ only) -libjsonnet_test_file libjsonnet_test_snippet: %: .makebuild/core/%.c.o libjsonnet.so - $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(TEST_RPATH_FLAG) # C++ tests of the C API (link to libjsonnet.so) libjsonnet_test: %: .makebuild/core/%.cpp.o libjsonnet.so $(CXX) $(CXXFLAGS) $(GTEST_CXXFLAGS) -o $@ $^ $(LDFLAGS) $(GTEST_LDFLAGS) $(TEST_RPATH_FLAG) @@ -237,4 +271,9 @@ unicode_test: %: .makebuild/core/%.cpp.o parser_test: %: .makebuild/core/%.cpp.o .makebuild/core/parser.cpp.o .makebuild/core/lexer.cpp.o $(CXX) $(CXXFLAGS) $(GTEST_CXXFLAGS) -o $@ $^ $(LDFLAGS) $(GTEST_LDFLAGS) +endif # GTEST_ENABLED + +# +### + -include $(DEPS_FILES) diff --git a/tests.sh b/tests.sh index e5e54b4dc..f68790f0a 100755 --- a/tests.sh +++ b/tests.sh @@ -11,12 +11,13 @@ if [ -z "$DISABLE_LIB_TESTS" ]; then ./libjsonnet_test_snippet "${TEST_SNIPPET}" || FAIL=TRUE printf 'libjsonnet_test_file: ' ./libjsonnet_test_file "test_suite/object.jsonnet" || FAIL=TRUE + + for gtest_bin in unicode_test lexer_test parser_test libjsonnet_test libjsonnet++_test; do + if [[ -x "./${gtest_bin}" ]]; then + "./${gtest_bin}" || FAIL=true + fi + done fi -./unicode_test || FAIL=TRUE -./lexer_test || FAIL=TRUE -./parser_test || FAIL=TRUE -./libjsonnet_test || FAIL=TRUE -./libjsonnet++_test || FAIL=TRUE examples/check.sh || FAIL=TRUE examples/terraform/check.sh || FAIL=TRUE test_cmd/run_cmd_tests.sh || FAIL=TRUE From eebff0edf59d7f03c7511e0af551da4fcf184418 Mon Sep 17 00:00:00 2001 From: John Bartholomew Date: Sun, 8 Feb 2026 22:06:53 +0000 Subject: [PATCH 3/4] Makefile: skip building manpages if help2man is not found --- Makefile | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Makefile b/Makefile index 6fb6b751d..2380c8401 100644 --- a/Makefile +++ b/Makefile @@ -55,6 +55,11 @@ GTEST_CXXFLAGS := $(shell pkg-config --cflags '$(GTEST_PKG)') GTEST_LDFLAGS := $(shell pkg-config --libs '$(GTEST_PKG)') endif +HELP2MAN_FOUND := $(shell command -v '$(HELP2MAN)' > /dev/null 2>&1 && echo yes || echo no) +ifneq ($(HELP2MAN_FOUND),yes) +$(warning help2man was not found under the name $(HELP2MAN); manpages will not be built.) +endif + ifeq ($(origin GTEST_ENABLED),undefined) GTEST_ENABLED := $(GTEST_FOUND) ifeq ($(GTEST_ENABLED),no) @@ -216,11 +221,17 @@ CC_DEPS_FLAGS = -MMD -MP -MF "$(addsuffix .d,$@)" %.so: %.so.$(SOVERSION) ln -sf $< $@ +ifeq ($(HELP2MAN_FOUND),yes) $(MAN_PAGES): $(MAN1_DIR)/%.1: % | $(MAN1_DIR) $(HELP2MAN) --no-info --output=$@ ./$< $(MAN1_DIR): mkdir -p $@ +else +.PHONY: $(MAN1_DIR) $(MAN_PAGES) +$(MAN1_DIR) $(MAN_PAGES): + @{ >&2 echo "Skipping $@: Cannot build manpages, help2man was not found." ; } +endif jsonnet: .makebuild/cmd/jsonnet.cpp.o .makebuild/cmd/utils.cpp.o $(LIB_OBJ) $(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) From eee9ff61f28aebed7ec3f26186faf3cbbcc3e470 Mon Sep 17 00:00:00 2001 From: John Bartholomew Date: Sun, 8 Feb 2026 22:27:35 +0000 Subject: [PATCH 4/4] update Makefile CI build to install GoogleTest and help2man --- .github/workflows/build_and_test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index cca4c2986..cd1db380d 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -34,6 +34,9 @@ jobs: runs-on: "ubuntu-22.04" steps: - uses: actions/checkout@v4 + - name: Add system tools + run: | + sudo apt-get update && sudo apt-get install libgtest-dev help2man - name: Build (make all) run: | make all