Makefile 14.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
# -*- Mode: BSDmakefile; -*-                                          
#
# Makefile for Rosie Pattern Language
#
# © Copyright IBM Corporation 2018.
# LICENSE: MIT License (https://opensource.org/licenses/mit-license.html)
# AUTHOR: Jamie A. Jennings
#
#
# 'make' builds rosie within the current directory.
#    bin/rosie is the rosie command line program.
#    src/librosie/binaries contains librosie.so/dylib and librosie.a.
#    src/librosie/python, src/librosie/go, etc. contain sample librosie clients.
#
# 'make install' builds rosie within the current directory, but
# configures librosie and the CLI to look for rosie files in DESTDIR
# (see default value below).  Then the installation files are copied to:
#    $DESTDIR/lib/librosie.a
#    $DESTDIR/lib/librosie.so (or .dylib on OS X)
20
#    $DESTDIR/include/librosie.h
21 22 23
#    $DESTDIR/lib/rosie/      (rosie files needed at runtime)
#    $DESTDIR/bin/rosie       (cli)
#
24
# 'make test' runs all of the blackbox and whitebox tests.
25 26 27 28
# For the tests to execute, rosie must have been built with as follows:
#    'make LUADEBUG=1'
#

29 30 31
# -----------------------------------------------------------------------------
# Customizable options
# -----------------------------------------------------------------------------
32

33
DESTDIR=/usr/local
34

35 36 37
# -----------------------------------------------------------------------------
# Platform detection
# -----------------------------------------------------------------------------
38

39 40 41 42 43 44
REPORTED_PLATFORM=$(shell (uname -o || uname -s) 2> /dev/null)
ifeq ($(REPORTED_PLATFORM), Darwin)
PLATFORM=macosx
else ifeq ($(REPORTED_PLATFORM), GNU/Linux)
PLATFORM=linux
else
45
$(error Unsupported platform (uname reported "$(REPORTED_PLATFORM)"))
46 47
endif

48 49 50 51
# -----------------------------------------------------------------------------
# References to places in the build directory
# -----------------------------------------------------------------------------

52
ROSIEBIN = $(BUILD_ROOT)/bin/rosie
53 54 55
RPEG_DIR = $(BUILD_ROOT)/src/rpeg
LIBROSIE_DIR = $(BUILD_ROOT)/src/librosie
SUBMOD_DIR = $(BUILD_ROOT)/submodules
56 57 58 59

LUA_DIR = $(SUBMOD_DIR)/$(LUA)
JSON_DIR = $(SUBMOD_DIR)/$(JSON)
LUAMOD_DIR = $(SUBMOD_DIR)/$(LUAMOD)
60
READLINE_DIR = $(SUBMOD_DIR)/$(READLINE)
61

62 63 64 65 66 67
LIBROSIE_A=librosie.a

ifeq ($(PLATFORM),macosx)
PLATFORM=macosx
CC=cc
LIBROSIE_DYLIB=librosie.dylib
68
else ifeq ($(PLATFORM),linux)
69 70 71 72
PLATFORM=linux
CC=gcc
LIBROSIE_DYLIB=librosie.so
endif
73

74 75
LIBROSIE_H=librosie.h

76
# Submodules
77
ARGPARSE = argparse
78 79
LUA = lua
JSON = lua-cjson
80
READLINE = lua-readline
81
LUAMOD = lua-modules
82

83
BUILD_ROOT = $(shell pwd)
84

85 86 87
# -----------------------------------------------------------------------------
# Install layout
# -----------------------------------------------------------------------------
88

89 90
LIBROSIED = $(DESTDIR)/lib
ROSIED = $(DESTDIR)/lib/rosie
91

92
# Almost everything gets copied to $(ROSIED): 
93 94
#   $(ROSIED)/bin          arch-dependent binaries (e.g. rosie, luac)
#   $(ROSIED)/lib          arch-dependent libraries (e.g. *.luac)
95 96
#   $(ROSIED)/rpl          standard library (*.rpl)
#   $(ROSIED)/doc          documentation (html format)
97
#   $(ROSIED)/extra        editor highlighting files, sample docker files, other things
98 99 100 101 102
#   $(ROSIED)/CHANGELOG    change log
#   $(ROSIED)/CONTRIBUTORS project contributors, acknowledgements
#   $(ROSIED)/LICENSE      license
#   $(ROSIED)/README       short text readme (e.g. where to open issues)
#   $(ROSIED)/VERSION      installed version
103
#
104 105
# Rosie executable is compiled during 'make install':
#   $(DESTDIR)/bin/rosie
106
#
107
# FUTURE: Links into $(ROSIED)
108 109 110
#   $(ROSIE_ROOT)/rpl  --> $(ROSIED)/rpl
#   $(ROSIE_ROOT)/pkg  --> $(ROSIED)/pkg
#   $(ROSIE_DOC)/rosie --> $(ROSIED)/doc
111

112
INSTALL_LIB_DIR = $(ROSIED)/lib
113
INSTALL_RPL_DIR = $(ROSIED)/rpl
114 115
INSTALL_DOC_DIR = $(ROSIED)/doc
INSTALL_EXTRA_DIR = $(ROSIED)/extra
116
INSTALL_MAN_DIR = $(DESTDIR)/share/man/man1
117
INSTALL_BIN_DIR = $(DESTDIR)/bin
118
INSTALL_INCLUDE_DIR = $(DESTDIR)/include
119
INSTALL_ROSIEBIN = $(INSTALL_BIN_DIR)/rosie
120

121 122 123
# -----------------------------------------------------------------------------
# Targets
# -----------------------------------------------------------------------------
124

125
ifdef ROSIE_HOME
126
ROSIE_HOME_GIVEN_ON_COMMAND_LINE = true
127 128
else
ROSIE_HOME="$(shell pwd)"
129 130
endif

131 132 133
.PHONY:
.NOTPARALLEL:
default: binaries compile sniff
134

135 136 137
# <sigh> Once we support packages (like RPM), we won't need this test.
# Note that this test should ALWAYS pass on OS X, since it ships with
# readline.
138
.PHONY: readlinetest
139
readlinetest:
140
	@(bash -c 'printf "#include <stdio.h>\n#include <readline/readline.h>\nint main() { }\n"' | \
141
	           $(CC) -std=c99 -lreadline -o /dev/null -xc -) && \
142
	   echo 'readline TEST: libreadline and readline.h appear to be installed' || \
143
	   (echo '**'; echo '** readline TEST: Missing readline library or readline.h'; echo '**' && /usr/bin/false)
144

145 146 147
# When we compile with gcc, such as on linux, we need bsd/stdio.h to
# compile rpeg.  We check for it here so that we can give a useful
# error message.
148 149
.PHONY: libbsdtest
libbsdtest:
150
	@(bash -c 'printf "#if defined(__linux__)\n#if !defined(__clang__)\n#include <bsd/stdio.h>\n#endif\n#endif\nint main() { }\n"' | \
151 152
	           $(CC) -std=c99 -o /dev/null -xc -) && \
	   echo 'libbsd TEST: bsd/stdio.h appears to be installed (or is not needed)' || \
153
	   (echo '**'; echo '** libbsd TEST: Missing bsd/stdio.h.  Try running: apt-get install libbsd'; echo '**' && /usr/bin/false)
154

155 156 157
# The submodule_sentinel indicates that submodules have been
# initialized in the git sense, i.e. that they have been cloned.  The
# sentile file is a file copied from a submodule repo, so that:
158 159 160
# (1) the submodule must have been checked out, and
# (2) the sentinel will not be newer than the submodule files
submodule_sentinel=submodules/~~present~~ 
161 162
submodules = submodules/lua/src/Makefile \
		submodules/lua-cjson/Makefile \
163 164
		submodules/lua-readline/Makefile
$(submodules): $(submodule_sentinel) readlinetest
165

166
.PHONY:
167
$(submodule_sentinel): 
168 169
	if [ -z $$BREW ]; then git submodule init; fi
	if [ -z $$BREW ]; then git submodule update --checkout; fi
170
	cd $(LUA_DIR) && rm -f include && ln -sf src include
171
	cp -p $(LUA_DIR)/README $(submodule_sentinel)
172
	@$(BUILD_ROOT)/src/build_info.sh "git_submodules" $(BUILD_ROOT) "git" >> $(BUILD_ROOT)/build.log
173

Jamie Jennings's avatar
Jamie Jennings committed
174
bin/luac: $(LUA_DIR)/src/lua
175
	mkdir -p bin
Jamie Jennings's avatar
Jamie Jennings committed
176
	cp $(LUA_DIR)/src/luac bin
177 178

$(LUA_DIR)/src/lua: $(submodules)
179
	$(MAKE) -C "$(LUA_DIR)" CC=$(CC) $(PLATFORM) $(LINUX_CFLAGS) $(LINUX_LDFLAGS)
180
	@$(BUILD_ROOT)/src/build_info.sh "lua" $(BUILD_ROOT) $(CC) >> $(BUILD_ROOT)/build.log
181

182
## ----------------------------------------------------------------------------------------
183

184 185
json_lib=$(JSON_DIR)/cjson.so
lib/cjson.so: $(json_lib) 
186

Jamie A. Jennings's avatar
Jamie A. Jennings committed
187
$(json_lib): $(submodules) 
188
	$(MAKE) -C "$(JSON_DIR)" CC=$(CC)
189
	@$(BUILD_ROOT)/src/build_info.sh "json" $(BUILD_ROOT) $(CC) >> $(BUILD_ROOT)/build.log
190

191 192
lib/argparse.luac: $(submodules) submodules/argparse/src/argparse.lua bin/luac
	bin/luac -o lib/argparse.luac submodules/argparse/src/argparse.lua
193
	@$(BUILD_ROOT)/src/build_info.sh "argparse" $(BUILD_ROOT) "bin/luac" >> $(BUILD_ROOT)/build.log
194

195
readline_lib = $(READLINE_DIR)/readline.so
196
lib/readline.so: $(readline_lib) 
197

198
$(READLINE_DIR)/readline.so: $(submodules)
199
	$(MAKE) -C "$(READLINE_DIR)" CC=$(CC) LUADIR=../$(LUA)
200
	@$(BUILD_ROOT)/src/build_info.sh "readline_stub" $(BUILD_ROOT) $(CC) >> $(BUILD_ROOT)/build.log
201

202
lib/strict.luac: $(LUAMOD_DIR)/strict.lua bin/luac
203
	bin/luac -o $@ $<
204

205
lib/list.luac: $(LUAMOD_DIR)/list.lua bin/luac
206
	bin/luac -o $@ $<
207

208
lib/thread.luac: $(LUAMOD_DIR)/thread.lua bin/luac
209
	bin/luac -o $@ $<
210

211
lib/recordtype.luac: $(LUAMOD_DIR)/recordtype.lua bin/luac
212
	bin/luac -o $@ $<
213

214
lib/submodule.luac: $(LUAMOD_DIR)/submodule.lua bin/luac
215
	bin/luac -o $@ $<
216

217
lib/%.luac: src/lua/%.lua bin/luac
218
	@mkdir -p lib
219
	bin/luac -o $@ $<
220
	@$(BUILD_ROOT)/src/build_info.sh $@ $(BUILD_ROOT) "bin/luac" >> $(BUILD_ROOT)/build.log
221

222
core_objects := $(patsubst src/lua/%.lua,lib/%.luac,$(wildcard src/lua/*.lua))
223
other_objects := lib/argparse.luac lib/list.luac lib/recordtype.luac lib/submodule.luac lib/strict.luac lib/thread.luac
224
luaobjects := $(core_objects) $(other_objects)
225

226
compile: binaries $(luaobjects) bin/luac $(json_lib) $(readline_lib)
227 228

.PHONY:
229
binaries: libbsdtest $(luaobjects) $(json_lib) $(readline_lib)
230
	@$(MAKE) -C $(LIBROSIE_DIR) ROSIE_HOME="$(ROSIE_HOME)"
231
	$(BUILD_ROOT)/src/build_info.sh "binaries" $(BUILD_ROOT) $(CC) >> $(BUILD_ROOT)/build.log
232

233
$(ROSIEBIN): binaries $(LIBROSIE_DIR)/binaries/rosie
234
	cp $(LIBROSIE_DIR)/binaries/rosie "$(BUILD_ROOT)/bin/rosie"
235 236 237 238

# -----------------------------------------------------------------------------
# Install
# -----------------------------------------------------------------------------
239

240
# Main install rule
241
.PHONY: install installforce 
242
install:
243
	@if [ -L "$(ROSIED)" ]; then \
244 245
		echo "$(ROSIED) exists and is a symbolic link."; \
		echo "If rosie was installed with 'brew', then run 'brew uninstall rosie'."; \
246
		echo "Or run 'make installforce' to overwrite the current installation."; \
247 248
		exit -1; \
	elif [ -e "$(ROSIED)" ]; then \
249
		echo "$(ROSIED) already exists. Run 'make installforce' to overwrite it."; \
250
		exit -1; \
251
	elif [ -e "$(DESTDIR)/bin/rosie" ]; then \
252
		echo "$(DESTDIR)/bin/rosie already exists. Run 'make installforce' to overwrite it."; \
253
		exit -1; \
254
	else \
255 256
		echo "Installing..."; \
		$(MAKE) installforce; \
257 258
	fi;

259 260
installforce: ROSIE_HOME = "$(DESTDIR)/lib/rosie"
installforce: $(INSTALL_ROSIEBIN) binaries install_metadata install_luac_bin install_rpl install_librosie install_doc install_extras install_man
261

262 263 264
# We use mv instead of cp for all the binaries, so that the binaries
# will be rebuilt every time "make install" is run, in case DESTDIR
# has changed.
265

266
$(INSTALL_ROSIEBIN): compile binaries
267
	mkdir -p "$(INSTALL_BIN_DIR)"
268
	-rm -f "$(INSTALL_ROSIEBIN)"
269
	cp "$(LIBROSIE_DIR)/binaries/rosie" "$(INSTALL_ROSIEBIN)"
270
	rm -f "$(LIBROSIE_DIR)/binaries/rosie"
271

272 273 274
# Install librosie
.PHONY: install_librosie
install_librosie: compile binaries
275
	-rm -f "$(LIBROSIED)/$(LIBROSIE_DYLIB)"
276
	cp "$(LIBROSIE_DIR)/binaries/$(LIBROSIE_DYLIB)" "$(LIBROSIED)/$(LIBROSIE_DYLIB)"
277 278
	rm -f "$(LIBROSIE_DIR)/binaries/$(LIBROSIE_DYLIB)"
	-rm -f "$(LIBROSIED)/$(LIBROSIE_A)"
279
	cp "$(LIBROSIE_DIR)/binaries/$(LIBROSIE_A)" "$(LIBROSIED)/$(LIBROSIE_A)"
280
	rm -f "$(LIBROSIE_DIR)/binaries/$(LIBROSIE_A)"
281
	cp "$(LIBROSIE_DIR)/$(LIBROSIE_H)" "$(INSTALL_INCLUDE_DIR)"
282

283
# Install any metadata needed by rosie.  In case $(ROSIED) is a symlink, we try to rm it first.
284 285
.PHONY: install_metadata
install_metadata:
286
	-rm -f "$(ROSIED)"
287
	mkdir -p "$(ROSIED)"
288
	cp CHANGELOG CONTRIBUTORS LICENSE README VERSION "$(ROSIED)"
289
	-cp $(BUILD_ROOT)/build.log "$(ROSIED)"
290 291 292 293

# Install the lua pre-compiled binary files (.luac)
.PHONY: install_luac_bin
install_luac_bin:
294 295
	mkdir -p "$(INSTALL_LIB_DIR)"
	cp lib/*.luac "$(INSTALL_LIB_DIR)"
296

297
# TODO: Parameterize this, or use a wildcard
298 299 300
# Install the provided RPL patterns
.PHONY: install_rpl
install_rpl:
301 302 303 304
	mkdir -p "$(INSTALL_RPL_DIR)"
	cp rpl/*.rpl "$(INSTALL_RPL_DIR)"
	mkdir -p "$(INSTALL_RPL_DIR)"/rosie
	cp rpl/rosie/*.rpl "$(INSTALL_RPL_DIR)"/rosie/
305 306 307 308
	mkdir -p "$(INSTALL_RPL_DIR)"/builtin
	cp rpl/builtin/*.rpl "$(INSTALL_RPL_DIR)"/builtin/
	mkdir -p "$(INSTALL_RPL_DIR)"/Unicode
	cp rpl/Unicode/*.rpl "$(INSTALL_RPL_DIR)"/Unicode/
309

310 311 312 313 314 315 316 317 318 319
.PHONY: install_doc
install_doc:
	mkdir -p "$(INSTALL_DOC_DIR)"
	cp -R doc/ "$(INSTALL_DOC_DIR)"

.PHONY: install_extras
install_extras:
	mkdir -p "$(INSTALL_EXTRA_DIR)"
	cp -R extra/ "$(INSTALL_EXTRA_DIR)"

320 321 322 323 324
.PHONY: install_man
install_man:
	mkdir -p "$(INSTALL_MAN_DIR)"
	cp doc/man/rosie.1 "$(INSTALL_MAN_DIR)"

325 326 327
# -----------------------------------------------------------------------------
# Uninstall
# -----------------------------------------------------------------------------
328 329 330 331 332 333 334

.PHONY: uninstall
uninstall:
	@echo "Removing $(INSTALL_ROSIEBIN)"
	@-rm -vf $(INSTALL_ROSIEBIN)
	@echo "Removing $(ROSIED)"
	@-rm -Rvf $(ROSIED)/
335
	@echo "Removing librosie.a/.so/.dylib from $(LIBROSIED)"
336
	@-rm -vf "$(LIBROSIED)/$(LIBROSIE_DYLIB)"
337
	@-rm -vf "$(LIBROSIED)/$(LIBROSIE_A)"
338 339
	@echo "Removing librosie.h from $(INSTALL_INCLUDE_DIR)"
	@-rm -vf "$(INSTALL_INCLUDE_DIR)/$(LIBROSIE_H)" 
340 341
	@echo "Removing rosie man page $(INSTALL_MAN_DIR)"
	@-rm -vf "$(INSTALL_MAN_DIR)/rosie.1"
342 343 344

.PHONY: sniff
sniff: $(ROSIEBIN)
345
	@if [ -n "$(ROSIE_HOME_GIVEN_ON_COMMAND_LINE)" ]; then \
346 347
	    echo "Rosie Pattern Engine was built with a custom ROSIE_HOME path: $(ROSIE_HOME)"; \
	    echo "Skipping sniff test of CLI due to custom path."; \
348 349 350
	    true; \
	else \
	RESULT="$(shell $(ROSIEBIN) version 2> /dev/null)"; \
351
	EXPECTED="$(shell head -1 $(BUILD_ROOT)/VERSION)"; \
352
	if [ -n "$$RESULT" -a "$$RESULT" = "$$EXPECTED" ]; then \
353
	    echo "";\
354
            echo "Rosie Pattern Engine $$RESULT built successfully!"; \
355
	    if [ -z "$$BREW" ]; then \
356 357
	      	    echo "    Use 'make install' to install into DESTDIR=$(DESTDIR)"; \
	      	    echo "    Use 'make uninstall' to uninstall from DESTDIR=$(DESTDIR)"; \
358
	      	    echo "    To run rosie from the build directory, use ./bin/rosie"; \
359
	            echo "    Try this example, and look for color text output: rosie match all.things test/resolv.conf"; \
360
		    echo "";\
361
	    fi; \
362
            true; \
363
        else \
364
            echo "Rosie Pattern Engine test FAILED."; \
365
	    echo "    Rosie executable is $(ROSIEBIN)"; \
366 367 368 369
	    echo "    Expected this output: $$EXPECTED"; \
	    if [ -n "$$RESULT" ]; then \
		echo "    But received this output: $$RESULT"; \
	    else \
370
		echo "    But received no output to stdout."; \
371
	    fi; \
372
	    false; \
373 374
        fi; \
	fi
375

376 377 378 379 380 381 382
# -----------------------------------------------------------------------------
# Tests need to be done with dumb terminal type because the cli and
# repl tests compare the expected output to the actual output byte by
# byte.  With other terminal types, the ANSI color codes emitted by
# Rosie can be munged by the terminal, making some tests fail when
# they should not.

383
.PHONY: test
384
test:
385
	@$(BUILD_ROOT)/test/rosie-has-debug.sh $(ROSIEBIN) 2>/dev/null; \
386 387
	if [ "$$?" -ne "0" ]; then \
	echo "Rosie was not built with LUADEBUG support.  Try 'make clean; make LUADEBUG=1'."; \
388
	exit -1; \
389
	fi;
390
	@echo Running tests in test/all.lua
391
	@(TERM="dumb"; echo "dofile \"$(BUILD_ROOT)/test/all.lua\"" | $(ROSIEBIN) -D)
392

393
.PHONY: clean
394 395
clean: libclean
	rm -rf bin/* lib/* 
396 397 398 399
	-cd $(LUA_DIR) && make clean
	-cd $(JSON_DIR) && make clean
	-cd $(READLINE_DIR) && rm -f readline.so && rm -f src/lua_readline.o
	rm -f build.log
400

401 402 403 404 405 406 407
.PHONY: libclean
libclean:
	rm -rf librosie.so librosie.dylib librosie.a
	$(MAKE) -C "$(RPEG_DIR)" clean
	-cd $(LIBROSIE_DIR) && make clean