aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.md20
-rw-r--r--Makefile48
-rw-r--r--docs/README.md1
-rw-r--r--docs/libraries.md4
-rw-r--r--docs/tomo.1.md2
-rw-r--r--docs/versions.md71
-rw-r--r--examples/colorful/CHANGES.md5
-rw-r--r--examples/colorful/README.md2
-rw-r--r--examples/colorful/colorful.tm2
-rw-r--r--examples/coroutines/CHANGES.md5
-rw-r--r--examples/coroutines/README.md2
-rw-r--r--examples/game/CHANGES.md5
-rw-r--r--examples/http-server/CHANGES.md5
-rw-r--r--examples/http-server/connection-queue.tm2
-rw-r--r--examples/http-server/http-server.tm6
-rwxr-xr-xexamples/http-server/sample-site/random.tm2
-rw-r--r--examples/http/CHANGES.md5
-rw-r--r--examples/ini/CHANGES.md5
-rw-r--r--examples/ini/ini.tm2
-rw-r--r--examples/log/CHANGES.md5
-rw-r--r--examples/tomo-install/CHANGES.md5
-rw-r--r--examples/tomo-install/tomo-install.tm4
-rw-r--r--examples/tomodeps/CHANGES.md5
-rw-r--r--examples/tomodeps/tomodeps.tm2
-rw-r--r--examples/vectors/CHANGES.md5
-rw-r--r--examples/wrap/CHANGES.md5
-rw-r--r--lib/base64/CHANGES.md5
-rw-r--r--lib/commands/CHANGES.md5
-rw-r--r--lib/core/CHANGES.md5
-rw-r--r--lib/core/core.tm12
-rw-r--r--lib/patterns/CHANGES.md5
-rw-r--r--lib/patterns/_test.tm2
-rw-r--r--lib/patterns/patterns.c1
-rw-r--r--lib/pthreads/CHANGES.md5
-rw-r--r--lib/random/CHANGES.md5
-rw-r--r--lib/shell/CHANGES.md5
-rw-r--r--lib/shell/README.md2
-rw-r--r--lib/shell/shell.tm2
-rw-r--r--lib/time/CHANGES.md5
-rw-r--r--lib/uuid/CHANGES.md5
-rw-r--r--lib/uuid/uuid.tm4
-rw-r--r--link_versions.sh17
-rwxr-xr-xlocal-tomo5
-rw-r--r--src/compile.c8
-rw-r--r--src/stdlib/print.h2
-rw-r--r--src/stdlib/stacktrace.c2
-rw-r--r--src/tomo.c60
-rw-r--r--src/typecheck.c2
48 files changed, 314 insertions, 75 deletions
diff --git a/CHANGES.md b/CHANGES.md
new file mode 100644
index 00000000..b89c0751
--- /dev/null
+++ b/CHANGES.md
@@ -0,0 +1,20 @@
+# Version History
+
+## v0.3
+
+- Added a versioning system based on CHANGES.md files.
+
+## v0.2
+
+- Improved compatibility on different platforms.
+- Switched to use a per-file unique ID suffix instead of renaming symbols after
+ compilation with `objcopy`.
+- Installation process now sets user permissions as needed, which fixes an
+ issue where a user not in the sudoers file couldn't install even to a local
+ directory.
+- Fixed some bugs with Table and Text hashing.
+- Various other bugfixes and internal optimizations.
+
+## v0.1
+
+First version to get a version number.
diff --git a/Makefile b/Makefile
index 49df2d5e..e5baef93 100644
--- a/Makefile
+++ b/Makefile
@@ -67,10 +67,11 @@ OSFLAGS != case $(OS) in *BSD|Darwin) echo '-D_BSD_SOURCE';; Linux) echo '-D_GNU
EXTRA=
G=-ggdb
O=-O3
-GIT_VERSION=$(shell git log -1 --pretty=format:"$$(git describe --tags --abbrev=0)_%as_%h")
+TOMO_VERSION=$(shell awk '/^## / {print $$2; exit}' CHANGES.md)
+GIT_VERSION=$(shell git log -1 --pretty=format:"%as_%h")
CFLAGS=$(CCONFIG) $(INCLUDE_DIRS) $(EXTRA) $(CWARN) $(G) $(O) $(OSFLAGS) $(LTO) \
-DTOMO_PREFIX='"$(PREFIX)"' -DSUDO='"$(SUDO)"' -DDEFAULT_C_COMPILER='"$(DEFAULT_C_COMPILER)"' \
- -DTOMO_VERSION='"$(GIT_VERSION)"'
+ -DTOMO_VERSION='"$(TOMO_VERSION)"' -DGIT_VERSION='"$(GIT_VERSION)"'
CFLAGS_PLACEHOLDER="$$(printf '\033[2m<flags...>\033[m\n')"
LDLIBS=-lgc -lcord -lm -lunistring -lgmp -ldl
LIBTOMO_FLAGS=-shared
@@ -87,16 +88,17 @@ ifeq ($(OS),OpenBSD)
LDLIBS += -lexecinfo
endif
-AR_FILE=libtomo.a
+AR_FILE=libtomo_$(TOMO_VERSION).a
ifeq ($(OS),Darwin)
INCLUDE_DIRS += -I/opt/homebrew/include
LDFLAGS += -L/opt/homebrew/lib
- LIB_FILE=libtomo.dylib
- LIBTOMO_FLAGS += -Wl,-install_name,@rpath/libtomo.dylib
+ LIB_FILE=libtomo_$(TOMO_VERSION).dylib
+ LIBTOMO_FLAGS += -Wl,-install_name,@rpath/libtomo_$(TOMO_VERSION).dylib
else
- LIB_FILE=libtomo.so
- LIBTOMO_FLAGS += -Wl,-soname,libtomo.so
+ LIB_FILE=libtomo_$(TOMO_VERSION).so
+ LIBTOMO_FLAGS += -Wl,-soname,libtomo_$(TOMO_VERSION).so
endif
+EXE_FILE=tomo_$(TOMO_VERSION)
COMPILER_OBJS=$(patsubst %.c,%.o,$(wildcard src/*.c))
STDLIB_OBJS=$(patsubst %.c,%.o,$(wildcard src/stdlib/*.c))
@@ -104,7 +106,7 @@ TESTS=$(patsubst test/%.tm,test/results/%.tm.testresult,$(wildcard test/*.tm))
API_YAML=$(wildcard api/*.yaml)
API_MD=$(patsubst %.yaml,%.md,$(API_YAML))
-all: config.mk check-c-compiler check-libs build/lib/$(LIB_FILE) build/lib/$(AR_FILE) build/bin/tomo
+all: config.mk check-c-compiler check-libs build/lib/$(LIB_FILE) build/lib/$(AR_FILE) build/bin/$(EXE_FILE)
check-c-compiler:
@$(DEFAULT_C_COMPILER) -v 2>/dev/null >/dev/null \
@@ -114,7 +116,7 @@ check-libs: check-c-compiler
@echo 'int main() { return 0; }' | $(DEFAULT_C_COMPILER) $(LDFLAGS) $(LDLIBS) -x c - -o /dev/null 2>/dev/null >/dev/null \
|| { printf '\033[31;1m%s\033[m\n' "I expected to find the following libraries on your system, but I can't find them: $(LDLIBS)"; exit 1; }
-build/bin/tomo: $(STDLIB_OBJS) $(COMPILER_OBJS)
+build/bin/$(EXE_FILE): $(STDLIB_OBJS) $(COMPILER_OBJS)
@mkdir -p build/bin
@echo $(CC) $(CFLAGS_PLACEHOLDER) $(LDFLAGS) $^ $(LDLIBS) -o $@
@$(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@
@@ -134,14 +136,14 @@ tags:
config.mk: configure.sh
bash ./configure.sh
-%.o: %.c src/ast.h src/environment.h src/types.h config.mk
+%.o: %.c src/ast.h src/environment.h src/types.h config.mk CHANGES.md
@echo $(CC) $(CFLAGS_PLACEHOLDER) -c $< -o $@
@$(CC) $(CFLAGS) -c $< -o $@
%: %.tm
./local-tomo -e $<
-test/results/%.tm.testresult: test/%.tm build/bin/tomo
+test/results/%.tm.testresult: test/%.tm build/bin/$(EXE_FILE)
@mkdir -p test/results
@printf '\033[33;1;4m%s\033[m\n' $<
@if ! COLOR=1 LC_ALL=C ./local-tomo -O 1 $< 2>&1 | tee $@; then \
@@ -176,10 +178,10 @@ man/man1/tomo.1: docs/tomo.1.md
pandoc --lua-filter=docs/.pandoc/bold-code.lua -s $< -t man -o $@
examples:
- ./build/bin/tomo -qIL examples/log examples/ini examples/vectors examples/http examples/wrap examples/colorful
- ./build/bin/tomo -e examples/game/game.tm examples/http-server/http-server.tm \
+ ./local-tomo -qIL examples/log examples/ini examples/vectors examples/http examples/wrap examples/colorful
+ ./local-tomo -e examples/game/game.tm examples/http-server/http-server.tm \
examples/tomodeps/tomodeps.tm examples/tomo-install/tomo-install.tm
- ./build/bin/tomo examples/learnxiny.tm
+ ./local-tomo examples/learnxiny.tm
deps:
bash ./install_dependencies.sh
@@ -188,7 +190,7 @@ check-utilities: check-c-compiler
@which debugedit 2>/dev/null >/dev/null \
|| printf '\033[33;1m%s\033[m\n' "I couldn't find 'debugedit' on your system! Try installing the package 'debugedit' with your package manager. (It's not required though)"
-install-files: build/bin/tomo build/lib/$(LIB_FILE) build/lib/$(AR_FILE) check-utilities
+install-files: build/bin/$(EXE_FILE) build/lib/$(LIB_FILE) build/lib/$(AR_FILE) check-utilities
@if ! echo "$$PATH" | tr ':' '\n' | grep -qx "$(PREFIX)/bin"; then \
echo $$PATH; \
printf "\033[31;1mError: '$(PREFIX)/bin' is not in your \$$PATH variable!\033[m\n" >&2; \
@@ -198,15 +200,16 @@ install-files: build/bin/tomo build/lib/$(LIB_FILE) build/lib/$(AR_FILE) check-u
exit 1; \
fi
$(DEFINE_AS_OWNER); \
- as_owner mkdir -p -m 755 "$(PREFIX)/man/man1" "$(PREFIX)/man/man3" "$(PREFIX)/bin" "$(PREFIX)/include/tomo" "$(PREFIX)/lib"; \
- as_owner cp src/stdlib/*.h "$(PREFIX)/include/tomo/"; \
+ as_owner mkdir -p -m 755 "$(PREFIX)/man/man1" "$(PREFIX)/man/man3" "$(PREFIX)/bin" "$(PREFIX)/include/tomo_$(TOMO_VERSION)" "$(PREFIX)/lib"; \
+ as_owner cp src/stdlib/*.h "$(PREFIX)/include/tomo_$(TOMO_VERSION)/"; \
as_owner cp build/lib/$(LIB_FILE) build/lib/$(AR_FILE) "$(PREFIX)/lib/"; \
- as_owner rm -f "$(PREFIX)/bin/tomo"; \
- as_owner cp build/bin/tomo "$(PREFIX)/bin/"; \
+ as_owner rm -f "$(PREFIX)/bin/$(EXE_FILE)"; \
+ as_owner cp build/bin/$(EXE_FILE) "$(PREFIX)/bin/"; \
as_owner cp man/man1/* "$(PREFIX)/man/man1/"; \
- as_owner cp man/man3/* "$(PREFIX)/man/man3/";
+ as_owner cp man/man3/* "$(PREFIX)/man/man3/"; \
+ as_owner sh link_versions.sh
-install-libs: build/bin/tomo check-utilities
+install-libs: build/bin/$(EXE_FILE) check-utilities
$(DEFINE_AS_OWNER); \
./local-tomo -qIL lib/patterns lib/time lib/commands lib/shell lib/random lib/base64 lib/pthreads lib/uuid lib/core
@@ -214,7 +217,8 @@ install: install-files install-libs
uninstall:
$(DEFINE_AS_OWNER); \
- as_owner rm -rvf "$(PREFIX)/bin/tomo" "$(PREFIX)/include/tomo" "$(PREFIX)/lib/$(LIB_FILE)" "$(PREFIX)/lib/$(AR_FILE)" "$(PREFIX)/share/tomo";
+ as_owner rm -rvf "$(PREFIX)/bin/tomo" "$(PREFIX)/bin/tomo"[0-9]* "$(PREFIX)/bin/tomo_v"* "$(PREFIX)/include/tomo_v"* "$(PREFIX)/lib/libtomo_v*" "$(PREFIX)/share/tomo_$(TOMO_VERSION)"; \
+ as_owner sh link_versions.sh
endif
diff --git a/docs/README.md b/docs/README.md
index 017e344b..60aaf08f 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -14,6 +14,7 @@ A few topics that are documented:
- [Operator Overloading](operators.md)
- [Special Methods](metamethods.md)
- [C Interoperability](c-interoperability.md)
+- [Versioning](versions.md)
## Types
diff --git a/docs/libraries.md b/docs/libraries.md
index 7febb2e1..8043bfaa 100644
--- a/docs/libraries.md
+++ b/docs/libraries.md
@@ -151,8 +151,8 @@ that can be used by other Tomo projects. You can build a library by running
If you additionally add the `-I` flag, Tomo will copy the entire directory
(excluding files and directories that begin with `.` such as `.git`) into
-`~/.local/share/tomo/installed/` and create a symbolic link for the library's
-`.so` file (or `.dylib` file on Mac) in `~/.local/share/tomo/lib/`.
+`~/.local/share/tomo_vX.Y/installed/` (where `X` and `Y` are the major/minor
+version of the compiler).
### Using Shared Libraries
diff --git a/docs/tomo.1.md b/docs/tomo.1.md
index c77e91cf..7ccf0397 100644
--- a/docs/tomo.1.md
+++ b/docs/tomo.1.md
@@ -63,4 +63,4 @@ C code, which is then compiled using a C compiler of your choice.
: Print the compiler version and exit.
`-r`, `--run`
-: Run an installed tomo program from `~/.local/share/tomo/installed`.
+: Run an installed tomo program from `~/.local/share/tomo_vX.Y/installed`.
diff --git a/docs/versions.md b/docs/versions.md
new file mode 100644
index 00000000..b44902b2
--- /dev/null
+++ b/docs/versions.md
@@ -0,0 +1,71 @@
+# Versioning
+
+The Tomo language and Tomo libraries both use a versioning system based on a a
+changelog called `CHANGES.md` that includes a human-and-machine-readable
+markdown list of versions.
+
+The version number is parsed from the first level 2 header (i.e. line beginning
+with `## `). An example CHANGES.md file might look like this:
+
+```
+# Version History
+
+## v1.2
+
+Version 1.2 adds some new features:
+
+- Autofrobnication
+- Reverse froodling
+
+## v1.1
+
+- Added a `--moop` compiler flag
+
+## v1.0
+
+Major version change including:
+
+- Deprecated snobwozzling
+- Added new syntax for sleazles
+
+## v0.3
+
+Bugfixes and new features...
+```
+
+When you build the compiler or a library, if this file exists, it will be used
+to determine the current version (the top-most level 2 header).
+
+## Tomo Language Versions
+
+The version for the Tomo language itself will come into play in a few ways:
+
+1. The compiler will be installed to `tomo_vX.Y` (where `X` is the major
+ version number and `Y` is the minor version number).
+2. A symbolic link will be installed from `tomo` to the largest version of Tomo
+ that is installed on your machine (e.g. `~/.local/bin/tomo ->
+ ~/.local/bin/tomo_v2.12`).
+3. Each version of Tomo will build and install its own shared library file
+ (e.g. `~/.local/lib/libtomo_v1.2.so`) and headers (e.g.
+ `~/.local/include/tomo_v1.2/tomo.h`).
+4. Tomo libraries will be installed to a separate subdirectory for each version
+ of the compiler (e.g. `~/.local/share/tomo_v1.2/installed`).
+
+
+# Rationale
+
+I have opted to use a CHANGES.md file instead of git tags or a project
+configuration file for a few reasons. The first is that I think there is real
+value provided by maintaining a human-readable changelog. This approach
+encourages developers to maintain one. The second is to facilitate a development
+cycle where developers iterate on new features under the umbrella of a new
+version number, rather than the git tag-based approach where new features are
+developed in the no man's land between version tags. I also opted to use a
+human-readable markdown changelog rather than a build configuration file in
+order to ensure that there is no mismatch between the documentation and the
+configuration. My recommendation would be to develop code on a `main` or `dev`
+branch, bumping the version number pre-emptively (with an empty changelist). As
+new changes come in, add them to the changelog. Then, when it's appropriate,
+create a git tag to mark the current commit as the canonical one for that
+semantic version. Then, make a new commit after the tagged one bumping the
+version number and signaling the beginning of a new cycle of development.
diff --git a/examples/colorful/CHANGES.md b/examples/colorful/CHANGES.md
new file mode 100644
index 00000000..42ae752c
--- /dev/null
+++ b/examples/colorful/CHANGES.md
@@ -0,0 +1,5 @@
+# Version History
+
+## v1.0
+
+Initial version
diff --git a/examples/colorful/README.md b/examples/colorful/README.md
index c03ace24..04a221e3 100644
--- a/examples/colorful/README.md
+++ b/examples/colorful/README.md
@@ -55,7 +55,7 @@ colorful [--help] [texts...] [--by-line] [--files ...]
`colorful` can also be used as a Tomo library:
```tomo
-use colorful
+use colorful_v1.0
$Colorful"
@(blue:Welcome to the @(bold:party)!)
diff --git a/examples/colorful/colorful.tm b/examples/colorful/colorful.tm
index 9a8bbbba..270efe8c 100644
--- a/examples/colorful/colorful.tm
+++ b/examples/colorful/colorful.tm
@@ -7,7 +7,7 @@ HELP := "
CSI := "\033["
-use patterns
+use patterns_v1.0
lang Colorful
convert(text:Text -> Colorful)
diff --git a/examples/coroutines/CHANGES.md b/examples/coroutines/CHANGES.md
new file mode 100644
index 00000000..42ae752c
--- /dev/null
+++ b/examples/coroutines/CHANGES.md
@@ -0,0 +1,5 @@
+# Version History
+
+## v1.0
+
+Initial version
diff --git a/examples/coroutines/README.md b/examples/coroutines/README.md
index eef923e0..86b5dd00 100644
--- a/examples/coroutines/README.md
+++ b/examples/coroutines/README.md
@@ -6,7 +6,7 @@ This is a coroutine library built on top of a modified version of
## Example Usage
```tomo
-use coroutines
+use coroutines_v1.0
func main()
co := Coroutine(func()
diff --git a/examples/game/CHANGES.md b/examples/game/CHANGES.md
new file mode 100644
index 00000000..42ae752c
--- /dev/null
+++ b/examples/game/CHANGES.md
@@ -0,0 +1,5 @@
+# Version History
+
+## v1.0
+
+Initial version
diff --git a/examples/http-server/CHANGES.md b/examples/http-server/CHANGES.md
new file mode 100644
index 00000000..42ae752c
--- /dev/null
+++ b/examples/http-server/CHANGES.md
@@ -0,0 +1,5 @@
+# Version History
+
+## v1.0
+
+Initial version
diff --git a/examples/http-server/connection-queue.tm b/examples/http-server/connection-queue.tm
index c56069e1..5cf8bb91 100644
--- a/examples/http-server/connection-queue.tm
+++ b/examples/http-server/connection-queue.tm
@@ -1,4 +1,4 @@
-use pthreads
+use pthreads_v1.0
func _assert_success(name:Text, val:Int32; inline)
fail("$name() failed!") if val < 0
diff --git a/examples/http-server/http-server.tm b/examples/http-server/http-server.tm
index 80774bff..717aa733 100644
--- a/examples/http-server/http-server.tm
+++ b/examples/http-server/http-server.tm
@@ -9,9 +9,9 @@ use <unistd.h>
use <arpa/inet.h>
use <err.h>
-use commands
-use pthreads
-use patterns
+use commands_v1.0
+use pthreads_v1.0
+use patterns_v1.0
use ./connection-queue.tm
diff --git a/examples/http-server/sample-site/random.tm b/examples/http-server/sample-site/random.tm
index 153ac2af..75e185b3 100755
--- a/examples/http-server/sample-site/random.tm
+++ b/examples/http-server/sample-site/random.tm
@@ -1,5 +1,5 @@
#!/bin/env tomo
-use random
+use random_v1.0
func main()
say("
diff --git a/examples/http/CHANGES.md b/examples/http/CHANGES.md
new file mode 100644
index 00000000..42ae752c
--- /dev/null
+++ b/examples/http/CHANGES.md
@@ -0,0 +1,5 @@
+# Version History
+
+## v1.0
+
+Initial version
diff --git a/examples/ini/CHANGES.md b/examples/ini/CHANGES.md
new file mode 100644
index 00000000..42ae752c
--- /dev/null
+++ b/examples/ini/CHANGES.md
@@ -0,0 +1,5 @@
+# Version History
+
+## v1.0
+
+Initial version
diff --git a/examples/ini/ini.tm b/examples/ini/ini.tm
index 4dc27725..9bcfb3a4 100644
--- a/examples/ini/ini.tm
+++ b/examples/ini/ini.tm
@@ -1,5 +1,5 @@
-use patterns
+use patterns_v1.0
_USAGE := "
Usage: ini <filename> "[section[/key]]"
diff --git a/examples/log/CHANGES.md b/examples/log/CHANGES.md
new file mode 100644
index 00000000..42ae752c
--- /dev/null
+++ b/examples/log/CHANGES.md
@@ -0,0 +1,5 @@
+# Version History
+
+## v1.0
+
+Initial version
diff --git a/examples/tomo-install/CHANGES.md b/examples/tomo-install/CHANGES.md
new file mode 100644
index 00000000..42ae752c
--- /dev/null
+++ b/examples/tomo-install/CHANGES.md
@@ -0,0 +1,5 @@
+# Version History
+
+## v1.0
+
+Initial version
diff --git a/examples/tomo-install/tomo-install.tm b/examples/tomo-install/tomo-install.tm
index d915b993..e9838859 100644
--- a/examples/tomo-install/tomo-install.tm
+++ b/examples/tomo-install/tomo-install.tm
@@ -1,5 +1,5 @@
-use shell
-use patterns
+use shell_v1.0
+use patterns_v1.0
_USAGE := "
tomo-install file.tm...
diff --git a/examples/tomodeps/CHANGES.md b/examples/tomodeps/CHANGES.md
new file mode 100644
index 00000000..42ae752c
--- /dev/null
+++ b/examples/tomodeps/CHANGES.md
@@ -0,0 +1,5 @@
+# Version History
+
+## v1.0
+
+Initial version
diff --git a/examples/tomodeps/tomodeps.tm b/examples/tomodeps/tomodeps.tm
index 5513290c..af7f2573 100644
--- a/examples/tomodeps/tomodeps.tm
+++ b/examples/tomodeps/tomodeps.tm
@@ -1,6 +1,6 @@
# Show a Tomo dependency graph
-use patterns
+use patterns_v1.0
_USAGE := "Usage: tomodeps <files...>"
diff --git a/examples/vectors/CHANGES.md b/examples/vectors/CHANGES.md
new file mode 100644
index 00000000..42ae752c
--- /dev/null
+++ b/examples/vectors/CHANGES.md
@@ -0,0 +1,5 @@
+# Version History
+
+## v1.0
+
+Initial version
diff --git a/examples/wrap/CHANGES.md b/examples/wrap/CHANGES.md
new file mode 100644
index 00000000..42ae752c
--- /dev/null
+++ b/examples/wrap/CHANGES.md
@@ -0,0 +1,5 @@
+# Version History
+
+## v1.0
+
+Initial version
diff --git a/lib/base64/CHANGES.md b/lib/base64/CHANGES.md
new file mode 100644
index 00000000..42ae752c
--- /dev/null
+++ b/lib/base64/CHANGES.md
@@ -0,0 +1,5 @@
+# Version History
+
+## v1.0
+
+Initial version
diff --git a/lib/commands/CHANGES.md b/lib/commands/CHANGES.md
new file mode 100644
index 00000000..42ae752c
--- /dev/null
+++ b/lib/commands/CHANGES.md
@@ -0,0 +1,5 @@
+# Version History
+
+## v1.0
+
+Initial version
diff --git a/lib/core/CHANGES.md b/lib/core/CHANGES.md
new file mode 100644
index 00000000..42ae752c
--- /dev/null
+++ b/lib/core/CHANGES.md
@@ -0,0 +1,5 @@
+# Version History
+
+## v1.0
+
+Initial version
diff --git a/lib/core/core.tm b/lib/core/core.tm
index 6aa4c267..0b8aba53 100644
--- a/lib/core/core.tm
+++ b/lib/core/core.tm
@@ -1,9 +1,9 @@
# This file just uses all the most commonly used standard
# library modules so you don't have to import them one-by-one
-use patterns
-use commands
-use shell
-use pthreads
-use random
-use time
+use patterns_v1.0
+use commands_v1.0
+use shell_v1.0
+use pthreads_v1.0
+use random_v1.0
+use time_v1.0
diff --git a/lib/patterns/CHANGES.md b/lib/patterns/CHANGES.md
new file mode 100644
index 00000000..42ae752c
--- /dev/null
+++ b/lib/patterns/CHANGES.md
@@ -0,0 +1,5 @@
+# Version History
+
+## v1.0
+
+Initial version
diff --git a/lib/patterns/_test.tm b/lib/patterns/_test.tm
index 1a06570f..26c23628 100644
--- a/lib/patterns/_test.tm
+++ b/lib/patterns/_test.tm
@@ -1,4 +1,4 @@
-use patterns
+use patterns_v1.0
func main()
amelie := "Am\{UE9}lie"
diff --git a/lib/patterns/patterns.c b/lib/patterns/patterns.c
index 04cc9c0e..74d542b8 100644
--- a/lib/patterns/patterns.c
+++ b/lib/patterns/patterns.c
@@ -4,7 +4,6 @@
#include <string.h>
#include <strings.h>
#include <sys/param.h>
-#include <tomo/tomo.h>
#include <unictype.h>
#include <uniname.h>
#include <unistring/version.h>
diff --git a/lib/pthreads/CHANGES.md b/lib/pthreads/CHANGES.md
new file mode 100644
index 00000000..42ae752c
--- /dev/null
+++ b/lib/pthreads/CHANGES.md
@@ -0,0 +1,5 @@
+# Version History
+
+## v1.0
+
+Initial version
diff --git a/lib/random/CHANGES.md b/lib/random/CHANGES.md
new file mode 100644
index 00000000..42ae752c
--- /dev/null
+++ b/lib/random/CHANGES.md
@@ -0,0 +1,5 @@
+# Version History
+
+## v1.0
+
+Initial version
diff --git a/lib/shell/CHANGES.md b/lib/shell/CHANGES.md
new file mode 100644
index 00000000..42ae752c
--- /dev/null
+++ b/lib/shell/CHANGES.md
@@ -0,0 +1,5 @@
+# Version History
+
+## v1.0
+
+Initial version
diff --git a/lib/shell/README.md b/lib/shell/README.md
index 4adb8cff..d4bcd42e 100644
--- a/lib/shell/README.md
+++ b/lib/shell/README.md
@@ -3,7 +3,7 @@
This module defines a `lang` for running shell scripts:
```tomo
-use shell
+use shell_v1.0
>> $Shell"
seq 5
diff --git a/lib/shell/shell.tm b/lib/shell/shell.tm
index da03f843..f9476161 100644
--- a/lib/shell/shell.tm
+++ b/lib/shell/shell.tm
@@ -1,4 +1,4 @@
-use commands
+use commands_v1.0
lang Shell
convert(text:Text -> Shell)
diff --git a/lib/time/CHANGES.md b/lib/time/CHANGES.md
new file mode 100644
index 00000000..42ae752c
--- /dev/null
+++ b/lib/time/CHANGES.md
@@ -0,0 +1,5 @@
+# Version History
+
+## v1.0
+
+Initial version
diff --git a/lib/uuid/CHANGES.md b/lib/uuid/CHANGES.md
new file mode 100644
index 00000000..42ae752c
--- /dev/null
+++ b/lib/uuid/CHANGES.md
@@ -0,0 +1,5 @@
+# Version History
+
+## v1.0
+
+Initial version
diff --git a/lib/uuid/uuid.tm b/lib/uuid/uuid.tm
index 06d48390..f2be618e 100644
--- a/lib/uuid/uuid.tm
+++ b/lib/uuid/uuid.tm
@@ -1,5 +1,5 @@
-use random
-use time
+use random_v1.0
+use time_v1.0
lang UUID
func v4(-> UUID) # Random UUID
diff --git a/link_versions.sh b/link_versions.sh
new file mode 100644
index 00000000..3fadbe4f
--- /dev/null
+++ b/link_versions.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+TOMO_PREFIX="$(awk -F= '/PREFIX/{print $2}' config.mk)"
+cd "$TOMO_PREFIX/bin"
+
+commands="$(ls | awk -F '[v.]' '
+ /^tomo_v/{
+ if ($2 >= max_major) max_major=$2;
+ if ($3 >= max_minor[$2]) max_minor[$2] = $3;
+ link_tomo=1
+ }
+ END {
+ for (major in max_minor) {
+ if (max_major > 0) print "ln -fvs tomo_v"major"."max_minor[major]" tomo"major
+ }
+ if (link_tomo) print "ln -fvs tomo_v"max_major"."max_minor[max_major]" tomo"
+ }')"
+eval "$commands"
diff --git a/local-tomo b/local-tomo
index 9e89b15f..c7eaeb21 100755
--- a/local-tomo
+++ b/local-tomo
@@ -1,6 +1,7 @@
#!/bin/sh
+version=$(awk '/^## / {print $2; exit}' CHANGES.md)
here="$(realpath "$(dirname "$0")")"
-if [ ! -e "$here/build/bin/tomo" ]; then
+if [ ! -e "$here/build/bin/tomo_$version" ]; then
echo "Tomo hasn't been compiled yet! Run \`make\` to compile it!"
exit 1;
fi
@@ -10,4 +11,4 @@ LD_LIBRARY_PATH="$here/build/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" \
LIBRARY_PATH="$here/build/lib${LIBRARY_PATH:+:$LIBRARY_PATH}" \
C_INCLUDE_PATH="$here/build/include${C_INCLUDE_PATH:+:$C_INCLUDE_PATH}" \
CPATH="$here/build/include${CPATH:+:$CPATH}" \
-tomo "$@"
+tomo_"$version" "$@"
diff --git a/src/compile.c b/src/compile.c
index f3644488..98c0bdb0 100644
--- a/src/compile.c
+++ b/src/compile.c
@@ -1977,7 +1977,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast)
return with_source_info(env, ast, CORD_all("$initialize", suffix, "();\n"));
} else if (use->what == USE_MODULE) {
glob_t tm_files;
- if (glob(String(TOMO_PREFIX"/share/tomo/installed/", use->path, "/[!._0-9]*.tm"), GLOB_TILDE, NULL, &tm_files) != 0)
+ if (glob(String(TOMO_PREFIX"/share/tomo_"TOMO_VERSION"/installed/", use->path, "/[!._0-9]*.tm"), GLOB_TILDE, NULL, &tm_files) != 0)
code_err(ast, "Could not find library");
CORD initialization = CORD_EMPTY;
@@ -4457,7 +4457,7 @@ CORD compile_file(env_t *env, ast_t *ast)
return CORD_all(
env->do_source_mapping ? CORD_all("#line 1 ", CORD_quoted(ast->file->filename), "\n") : CORD_EMPTY,
"#define __SOURCE_FILE__ ", CORD_quoted(ast->file->filename), "\n",
- "#include <tomo/tomo.h>\n"
+ "#include <tomo_"TOMO_VERSION"/tomo.h>\n"
"#include \"", name, ".tm.h\"\n\n",
includes,
env->code->local_typedefs, "\n",
@@ -4484,7 +4484,7 @@ CORD compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast)
switch (use->what) {
case USE_MODULE: {
glob_t tm_files;
- if (glob(String(TOMO_PREFIX"/share/tomo/installed/", use->path, "/[!._0-9]*.tm"), GLOB_TILDE, NULL, &tm_files) != 0)
+ if (glob(String(TOMO_PREFIX"/share/tomo_"TOMO_VERSION"/installed/", use->path, "/[!._0-9]*.tm"), GLOB_TILDE, NULL, &tm_files) != 0)
code_err(ast, "Could not find library");
CORD includes = CORD_EMPTY;
@@ -4708,7 +4708,7 @@ CORD compile_file_header(env_t *env, Path_t header_path, ast_t *ast)
CORD header = CORD_all(
"#pragma once\n",
env->do_source_mapping ? CORD_all("#line 1 ", CORD_quoted(ast->file->filename), "\n") : CORD_EMPTY,
- "#include <tomo/tomo.h>\n");
+ "#include <tomo_"TOMO_VERSION"/tomo.h>\n");
compile_typedef_info_t info = {.env=env, .header=&header, .header_path=header_path};
visit_topologically(Match(ast, Block)->statements, (Closure_t){.fn=(void*)_make_typedefs, &info});
diff --git a/src/stdlib/print.h b/src/stdlib/print.h
index 9bd89aea..5ef5b6ed 100644
--- a/src/stdlib/print.h
+++ b/src/stdlib/print.h
@@ -150,6 +150,6 @@ FILE *gc_memory_stream(char **buf, size_t *size);
_fprint(_stream, __VA_ARGS__); \
fflush(_stream); \
_buf; })
-#define print_err(...) ({ fprint(stderr, __VA_ARGS__); exit(EXIT_FAILURE); })
+#define print_err(...) ({ fprint(stderr, "\033[31;1m", __VA_ARGS__, "\033[m"); exit(EXIT_FAILURE); })
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/stacktrace.c b/src/stdlib/stacktrace.c
index f4093849..3904ae70 100644
--- a/src/stdlib/stacktrace.c
+++ b/src/stdlib/stacktrace.c
@@ -102,7 +102,7 @@ public void print_stacktrace(FILE *out, int offset)
cwd[cwd_len++] = '/';
cwd[cwd_len] = '\0';
- const char *install_dir = TOMO_PREFIX"/share/tomo/installed/";
+ const char *install_dir = TOMO_PREFIX"/share/tomo_"TOMO_VERSION"/installed/";
static void *stack[1024];
int64_t size = (int64_t)backtrace(stack, sizeof(stack)/sizeof(stack[0]));
diff --git a/src/tomo.c b/src/tomo.c
index ebd33820..e11dbd23 100644
--- a/src/tomo.c
+++ b/src/tomo.c
@@ -82,8 +82,8 @@ static OptionalText_t
" -D_BSD_SOURCE"
#endif
" -DGC_THREADS"
- " -I'" TOMO_PREFIX "/include' -I'" TOMO_PREFIX "/share/tomo/installed' -I/usr/local/include"),
- ldlibs = Text("-lgc -lm -lgmp -lunistring -ltomo"),
+ " -I'" TOMO_PREFIX "/include' -I'" TOMO_PREFIX "/share/tomo_"TOMO_VERSION"/installed' -I/usr/local/include"),
+ ldlibs = Text("-lgc -lm -lgmp -lunistring -ltomo_"TOMO_VERSION),
ldflags = Text("-Wl,-rpath,'"TOMO_PREFIX"/lib',-rpath,/usr/local/lib"
" -L/usr/local/lib"),
optimization = Text("2"),
@@ -160,10 +160,10 @@ int main(int argc, char *argv[])
// Run a tool:
if ((streq(argv[1], "-r") || streq(argv[1], "--run")) && argc >= 3) {
if (strcspn(argv[2], "/;$") == strlen(argv[2])) {
- const char *program = String("'"TOMO_PREFIX"'/share/tomo/installed/", argv[2], "/", argv[2]);
+ const char *program = String("'"TOMO_PREFIX"'/share/tomo_"TOMO_VERSION"/installed/", argv[2], "/", argv[2]);
execv(program, &argv[2]);
}
- print_err("This is not an installed tomo program: \033[31;1m", argv[2], "\033[m");
+ print_err("This is not an installed tomo program: ", argv[2]);
}
Text_t usage = Text("\x1b[33;4;1mUsage:\x1b[m\n"
@@ -179,7 +179,7 @@ int main(int argc, char *argv[])
" --parse|-p: show parse tree\n"
" --install|-I: install the executable or library\n"
" --optimization|-O <level>: set optimization level\n"
- " --run|-r: run a program from " TOMO_PREFIX "/share/tomo/installed\n"
+ " --run|-r: run a program from " TOMO_PREFIX "/share/tomo_"TOMO_VERSION"/installed\n"
);
Text_t help = Texts(Text("\x1b[1mtomo\x1b[m: a compiler for the Tomo programming language"), Text("\n\n"), usage);
tomo_parse_args(
@@ -216,7 +216,10 @@ int main(int argc, char *argv[])
);
if (show_version) {
- print("Tomo version: ", TOMO_VERSION);
+ if (verbose)
+ print("Tomo version: ", TOMO_VERSION, " (", GIT_VERSION, ")");
+ else
+ print("Tomo version: ", TOMO_VERSION);
return 0;
}
@@ -249,7 +252,7 @@ int main(int argc, char *argv[])
for (int64_t i = 0; i < uninstall.length; i++) {
Text_t *u = (Text_t*)(uninstall.data + i*uninstall.stride);
- xsystem(as_owner, "rm -rvf '"TOMO_PREFIX"'/share/tomo/installed/", *u);
+ xsystem(as_owner, "rm -rvf '"TOMO_PREFIX"'/share/tomo_"TOMO_VERSION"/installed/", *u);
print("Uninstalled ", *u);
}
@@ -368,6 +371,27 @@ Path_t build_file(Path_t path, const char *extension)
return Path$with_component(build_dir, Texts(Path$base_name(path), Text$from_str(extension)));
}
+static Text_t get_version_suffix(Path_t lib_dir)
+{
+ Path_t changes_file = Path$with_component(lib_dir, Text("CHANGES.md"));
+ OptionalText_t changes = Path$read(changes_file);
+ if (changes.length <= 0) {
+ print_err("I couldn't find a valid CHANGES.md for the library in ", lib_dir, "\n"
+ "In order to install a library, it has to have a version defined in CHANGES.md\n"
+ "\n"
+ "Example CHANGES.md:\n"
+ "\n"
+ "# Version History\n"
+ "## v0.1\n"
+ "First version");
+ }
+ const char *changes_str = Text$as_c_string(Texts(Text("\n"), changes));
+ const char *version_line = strstr(changes_str, "\n## ");
+ if (version_line == NULL)
+ print_err("CHANGES.md in ", lib_dir, " does not have any valid versions starting with '## '");
+ return Texts(Text("_"), Text$from_strn(version_line + 4, strcspn(version_line + 4, "\r\n")));
+}
+
void build_library(Path_t lib_dir)
{
lib_dir = Path$resolved(lib_dir, Path$current_dir());
@@ -382,7 +406,8 @@ void build_library(Path_t lib_dir)
compile_files(env, tm_files, &object_files, &extra_ldlibs);
- Path_t shared_lib = Path$with_component(lib_dir, Texts(Text("lib"), lib_dir_name, Text(SHARED_SUFFIX)));
+ Text_t version_suffix = get_version_suffix(lib_dir);
+ Path_t shared_lib = Path$with_component(lib_dir, Texts(Text("lib"), lib_dir_name, version_suffix, Text(SHARED_SUFFIX)));
if (!is_stale_for_any(shared_lib, object_files)) {
if (verbose) whisper("Unchanged: ", shared_lib);
return;
@@ -390,9 +415,9 @@ void build_library(Path_t lib_dir)
FILE *prog = run_cmd(cc, " -O", optimization, " ", cflags, " ", ldflags, " ", ldlibs, " ", list_text(extra_ldlibs),
#ifdef __APPLE__
- " -Wl,-install_name,@rpath/'lib", lib_dir_name, SHARED_SUFFIX, "'"
+ " -Wl,-install_name,@rpath/'lib", lib_dir_name, version_suffix, SHARED_SUFFIX, "'"
#else
- " -Wl,-soname,'lib", lib_dir_name, SHARED_SUFFIX, "'"
+ " -Wl,-soname,'lib", lib_dir_name, version_suffix, SHARED_SUFFIX, "'"
#endif
" -shared ", paths_str(object_files), " -o '", shared_lib, "'");
@@ -409,7 +434,8 @@ void build_library(Path_t lib_dir)
void install_library(Path_t lib_dir)
{
Text_t lib_dir_name = Path$base_name(lib_dir);
- Path_t dest = Path$with_component(Path$from_str(TOMO_PREFIX"/share/tomo/installed"), lib_dir_name);
+ Text_t version_suffix = get_version_suffix(lib_dir);
+ Path_t dest = Path$with_component(Path$from_str(TOMO_PREFIX"/share/tomo_"TOMO_VERSION"/installed"), Texts(lib_dir_name, version_suffix));
if (!Path$equal_values(lib_dir, dest)) {
if (verbose) whisper("Clearing out any pre-existing version of ", lib_dir_name);
xsystem(as_owner, "rm -rf '", dest, "'");
@@ -423,10 +449,10 @@ void install_library(Path_t lib_dir)
if (verbose) whisper("Updating debug symbols for ", dest, "/lib", lib_dir_name, SHARED_SUFFIX);
int result = system(String(as_owner, "debugedit -b ", lib_dir,
" -d '", dest, "'"
- " '", dest, "/lib", lib_dir_name, SHARED_SUFFIX, "'"
- " 2>/dev/null >/dev/null"));
+ " '", dest, "/lib", lib_dir_name, version_suffix, SHARED_SUFFIX, "'"
+));
(void)result;
- print("Installed \033[1m", lib_dir_name, "\033[m to "TOMO_PREFIX"/share/tomo/installed");
+ print("Installed \033[1m", lib_dir_name, "\033[m to "TOMO_PREFIX"/share/tomo_"TOMO_VERSION"/installed/", lib_dir_name, version_suffix);
}
void compile_files(env_t *env, List_t to_compile, List_t *object_files, List_t *extra_ldlibs)
@@ -594,12 +620,12 @@ void build_file_dependency_graph(Path_t path, Table_t *to_compile, Table_t *to_l
}
case USE_MODULE: {
Text_t lib = Texts(Text("-Wl,-rpath,'"),
- Text(TOMO_PREFIX "/share/tomo/installed/"), Text$from_str(use->path),
- Text("' '" TOMO_PREFIX "/share/tomo/installed/"),
+ Text(TOMO_PREFIX "/share/tomo_"TOMO_VERSION"/installed/"), Text$from_str(use->path),
+ Text("' '" TOMO_PREFIX "/share/tomo_"TOMO_VERSION"/installed/"),
Text$from_str(use->path), Text("/lib"), Text$from_str(use->path), Text(SHARED_SUFFIX "'"));
Table$set(to_link, &lib, NULL, Table$info(&Text$info, &Void$info));
- List_t children = Path$glob(Path$from_str(String(TOMO_PREFIX"/share/tomo/installed/", use->path, "/*.tm")));
+ List_t children = Path$glob(Path$from_str(String(TOMO_PREFIX"/share/tomo_"TOMO_VERSION"/installed/", use->path, "/*.tm")));
for (int64_t i = 0; i < children.length; i++) {
Path_t *child = (Path_t*)(children.data + i*children.stride);
Table_t discarded = {.fallback=to_compile};
diff --git a/src/typecheck.c b/src/typecheck.c
index db3f392a..c80f6b2a 100644
--- a/src/typecheck.c
+++ b/src/typecheck.c
@@ -183,7 +183,7 @@ static env_t *load_module(env_t *env, ast_t *module_ast)
}
case USE_MODULE: {
glob_t tm_files;
- if (glob(String(TOMO_PREFIX"/share/tomo/installed/", use->path, "/[!._0-9]*.tm"), GLOB_TILDE, NULL, &tm_files) != 0)
+ if (glob(String(TOMO_PREFIX"/share/tomo_"TOMO_VERSION"/installed/", use->path, "/[!._0-9]*.tm"), GLOB_TILDE, NULL, &tm_files) != 0)
code_err(module_ast, "Could not find library");
env_t *module_env = fresh_scope(env);