andersch.dev

<2025-05-01 Thu>

build.sh

Build scripts like build.sh on Linux and build.bat on Windows are alternatives to fully-fledged build systems to automate the process of building software.

build.sh Template

  • [0/3] TODO: things to add
    • [ ] use Asan flags
    • [ ] better warnings
    • [ ] integrated file watching when run with dev
#!/bin/bash

# default values for envars
: "${CC:=clang++}" # compiler to use
: "${STD:=c++14}"  # standard to use

set -e # stop execution on first fail

# create needed directories
mkdir -p build

# if available, bear is used to (re)generate compile_commands.json
if [ "build.sh" -nt "compile_commands.json" ] && command -v bear >/dev/null; then
    rm --force compile_commands.json
    echo "Regenerating compile_commands.json"
    DB="bear --append --"
fi

CmnCompilerFlags="-I./src/ -g -DENABLE_ASSERTS -fPIC -fno-rtti -fno-exceptions -std=${STD} "
CmnCompilerFlags+="-Wall -Wfatal-errors -Wno-unused-function -Wno-unused-variable "
CmnLinkerFlags="-L. -Wl,-rpath=." # look for dynamic libraries in the current working dir

# build dll
${DB} ${CC} --shared ${CmnCompilerFlags} ${CmnLinkerFlags} main.cpp -o dylib.so

# add platform specific flags
CmnCompilerFlags+=" $(sdl2-config --cflags)"
CmnLinkerFlags+=" $(sdl2-config --libs) -ldl"

# precompiled header
HEADER_FILE="common.h"
PCH_FILE="common.pch"
if [ "$HEADER_FILE" -nt "$PCH_FILE" ]; then # Check if pch needs to be rebuilt
  ${DB} ${CC} -c ${CmnCompilerFlags} -x c++-header ${HEADER_FILE} -o ${PCH_FILE}
fi

# use pch when using clang
if [ $CC == "clang++" ]; then
  CmnCompilerFlags+=" -include-pch ${PCH_FILE} "
fi

# build executable
${DB} ${CC} ${CmnCompilerFlags} ${CmnLinkerFlags} -lGL ./src/platform.cpp -o ./build/main

Usage:

CC=g++ STD=c++26 ./build.sh

Combining build.sh and build.bat into one

Using the hack below, the same file can contain both a valid Windows batch script and Linux shell script. For best ergonomics, the file can be saved as a build.bat (enables Windows users to double-click it), and a build.sh symlinked to it.

echo >/dev/null # >nul & GOTO WINDOWS & rem ^

# linux compile command
cc -Wall main.c -o main -lGL

exit 0
:WINDOWS
@echo off

REM windows compile command
clang.exe -Wall main.c -o main.exe -lopengl32

build.bat on Linux using WINE

Download PortableBuildTools and run using:

wine ./PortableBuildTools.exe gui

cl.exe should now be in the PATH when using wine:

wine cmd /c cl.exe 2>/dev/null

Add following script called wine-batch (or similar):

#!/bin/bash
export WINEDEBUG=-all
exec wine cmd /c "$(winepath -w "$1")"

Add binfmt_misc handler to be able to run ./build.bat:

echo ':DOSBatch:E::bat::/path/to/wine-batch:' | sudo tee /proc/sys/fs/binfmt_misc/register

If it works, make it persistent by adding /etc/binfmt.d/bat.conf:

# Associate .bat files with Wine CMD (wine-batch is a wrapper script)
:DOSBatch:E::bat::/home/da/bin/wine-batch:

Now ./build.bat should work after calling sudo systemctl restart systemd-binfmt.

Resources