Running writefreely 0.7 on Arm
This is a follow-up on The expected tutorial: How to install WriteFreely on a Raspberry pi 3 in 10 steps. I will explain what was necessary to make cross-compiling work for newer WriteFreely versions with SQLite support.
I did it! I finally got WriteFreely to run on my Arm server (check out Scaleways baremetal cloud servers).
It wasn't so easy because with 512MB of RAM I couldn't simply download and build the source on my webserver. Only solution: Cross compiling. Easy especially in Go, right?
If you read the article linked in the beginning you know how easy it could be. But as the article already mentions in an update, since Version 0.6 it is not working anymore because of the new SQLite dependency (newest version as of writing this article is 0.7).
With a bit of research I figured out what to do to make it work anyhow. There are two solutions. A quick (and slightly dirty) one for people who don't need SQLite support and a correct solution that needs a tad more effort.
Quick solution: remove SQLite support
SQLite support makes problems with the cross compiling because it needs some C code to be compiled. Before figuring out how to make this working with the otherwise super easy Go cross compiling, removing the feature might be a viable quick fix. For this, simply change or remove all occurences of sqlite in the Makefile:
diff --git a/Makefile b/Makefile index 5950dfd..032fd0c 100644 --- a/Makefile +++ b/Makefile @@ -13,25 +13,25 @@ IMAGE_NAME=writeas/writefreely all : build build: assets deps - cd cmd/writefreely; $(GOBUILD) -v -tags='sqlite' + cd cmd/writefreely; $(GOBUILD) -v build-linux: deps @hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ $(GOGET) -u github.com/karalabe/xgo; \ fi - xgo --targets=linux/amd64, -dest build/ $(LDFLAGS) -tags='sqlite' -out writefreely ./cmd/writefreely + xgo --targets=linux/amd64, -dest build/ $(LDFLAGS) -out writefreely ./cmd/writefreely build-windows: deps @hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ $(GOGET) -u github.com/karalabe/xgo; \ fi - xgo --targets=windows/amd64, -dest build/ $(LDFLAGS) -tags='sqlite' -out writefreely ./cmd/writefreely + xgo --targets=windows/amd64, -dest build/ $(LDFLAGS) -out writefreely ./cmd/writefreely build-darwin: deps @hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ $(GOGET) -u github.com/karalabe/xgo; \ fi - xgo --targets=darwin/amd64, -dest build/ $(LDFLAGS) -tags='sqlite' -out writefreely ./cmd/writefreely + xgo --targets=darwin/amd64, -dest build/ $(LDFLAGS) -out writefreely ./cmd/writefreely build-docker : $(DOCKERCMD) build -t $(IMAGE_NAME):latest -t $(IMAGE_NAME):$(GITREV) . @@ -40,11 +40,11 @@ test: $(GOTEST) -v ./... run: dev-assets - $(GOINSTALL) -tags='sqlite' ./... + $(GOINSTALL) ./... $(BINARY_NAME) --debug deps : - $(GOGET) -tags='sqlite' -v ./... + $(GOGET) -v ./... install : build cmd/writefreely/$(BINARY_NAME) --gen-keys @@ -77,10 +77,10 @@ ui : force_look cd less/; $(MAKE) $(MFLAGS) assets : generate - go-bindata -pkg writefreely -ignore=\\.gitignore schema.sql sqlite.sql + go-bindata -pkg writefreely -ignore=\\.gitignore schema.sql dev-assets : generate - go-bindata -pkg writefreely -ignore=\\.gitignore -debug schema.sql sqlite.sql + go-bindata -pkg writefreely -ignore=\\.gitignore -debug schema.sql generate : @hash go-bindata > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
Now just go on as described in the original article and it should work:
env GOARCH=arm GOARM=7 go get github.com/writeas/writefreely/cmd/writefreely
The correct solution
To get WriteFreely cross compiled with SQLite support, a C cross compiler is needed. Void Linux, the distribution of my choice, offers a bunch of packages for all kind of architectures. They are called for example
cross-arm-linux-gnueabihf (ARMv6) or
cross-arm-linux-gnueabi (ARMv5). I found similar packages in AUR (for Arch Linux).
As soon as the corresponding cross compiler is found, go can be told to use it:
env CGO_ENABLED=1 CC=armv7l-linux-gnueabihf-gcc GOOS=linux GOARCH=arm GOARM=7 make
The environment variables used are:
CGO_ENABLED=1 should be obvious. It tells Go to enable the C compilation.
CC=armv... tells Go which C compiler to use. Usually this would be just
gcc. In this case it is the name of the cross compiler. Please set it to the compiler for your target platform. I'm going to use ARMv7 examples here. It is the name of a directory found in
/usr/armv7l-linux-gnueabihf. Initially that failed for me though because it expected to find a file
./lib/libc.so which ended up in another subfolder
/usr/. So I cheated a bit and did:
# You might not need to do this on your platform. sudo ln -s /usr/armv7l-linux-gnueabihf/usr/lib /usr/armv7l-linux-gnueabihf/lib
GOOS=linux GOARCH=arm are the same as in the original article.
GOARM=7 is optional, even on an actual ARMv7. It enables some register optimizations that only work on ARMv7.
make is called. This is short for
make all which should do everything necessary.
Not all files are necessary to be transferred to the Server or RaspberryPi. What I did after some experimentation was:
# after building everything create a package mkdir writefreely-arm cp -r templates pages static writefreely-arm mkdir writefreely-arm/keys # fun fact: key generation crashes without this cp cmd/writefreely/writefreely writefreely-arm tar cvzf writefreely-arm.tgz writefreely-arm # copy that package to the server scp writefreely-arm.tgz email@example.com:~ # ssh into the server and unpack everything ssh firstname.lastname@example.org tar czf writefreely-arm.tgz cd writefreely-arm # generate config, keys and database ./writefreely -config # starts interactive configuration # This should lead you through all necessary steps # like filling the config, generating keys, generating database tables # run `./writefreely --help` to learn more if something is missing.
./writefreely should run an empty blog at the specified port.