Skip to content

Commit 2029386

Browse files
authored
feat(build): Add new docker build and game install scripts for Linux (TheSuperHackers#2085)
Add convenience scripts for Linux users to build using Docker: - scripts/build-linux.sh: Docker-based build script for Linux that wraps the existing Docker infrastructure with Wine and VC6 toolchain - scripts/install-to-game.sh: Script to install built files to existing game installation with backup/restore support - .gitignore: Add /tmp/, /.claude/, /CLAUDE.md to ignored paths - README.md: Add quick start build section for Windows and Linux The Linux build uses the existing Docker infrastructure in resources/dockerbuild to produce Windows-compatible executables that can run under Wine. Usage: ./scripts/build-linux.sh # Build using Docker ./scripts/install-to-game.sh --detect # Install to your game
1 parent fcc193a commit 2029386

5 files changed

Lines changed: 712 additions & 4 deletions

File tree

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ thumbs.db
4747
.clang-format
4848
/.vscode
4949
/Dependencies/MaxSDK/maxsdk
50+
/tmp/
51+
52+
## AI assistant config (user-specific)
53+
/.claude/
54+
/CLAUDE.md
5055

5156
## IntelliJ, CLion, etc.
5257
/.idea

README.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,23 @@ report bugs, and contribute to the project!
6161

6262
## Building the Game Yourself
6363

64-
We provide support for building the project using Visual Studio 6 (VS6) and Visual Studio 2022. For detailed build
65-
instructions, check the [Wiki](https://github.com/TheSuperHackers/GeneralsGameCode/wiki/build_guides), which also
66-
includes guides for building with Docker, CLion, and links to forks supporting additional versions.
64+
We provide support for building the project on Windows and Linux. For detailed build instructions, check the
65+
[Wiki](https://github.com/TheSuperHackers/GeneralsGameCode/wiki/build_guides), which includes guides for VS6, VS2022,
66+
Docker, CLion, and links to forks supporting additional versions.
67+
68+
### Quick Start
69+
70+
**Windows (Visual Studio 2022)**
71+
```bash
72+
cmake --preset win32
73+
cmake --build build/win32 --config Release
74+
```
75+
76+
**Linux (via Docker)**
77+
```bash
78+
./scripts/docker-build.sh # Build using Docker
79+
./scripts/docker-install.sh --detect # Install to your game
80+
```
6781

6882
### Dependency management
6983

scripts/docker-build.sh

Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Build script for compiling Generals/Zero Hour on Linux using Docker
4+
#
5+
# This script builds Windows executables using a Docker container with Wine and VC6.
6+
# The resulting binaries can be run on Linux using Wine or on Windows natively.
7+
#
8+
# Usage:
9+
# ./scripts/docker-build.sh # Full build (both games)
10+
# ./scripts/docker-build.sh --game zh # Build Zero Hour only
11+
# ./scripts/docker-build.sh --game generals # Build Generals only
12+
# ./scripts/docker-build.sh --target generalszh # Build specific target
13+
# ./scripts/docker-build.sh --clean # Clean build directory
14+
# ./scripts/docker-build.sh --interactive # Enter container shell
15+
#
16+
17+
set -euo pipefail
18+
19+
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
20+
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
21+
BUILD_DIR="$PROJECT_DIR/build/docker"
22+
23+
# Colors for output
24+
RED='\033[0;31m'
25+
GREEN='\033[0;32m'
26+
YELLOW='\033[1;33m'
27+
BLUE='\033[0;34m'
28+
NC='\033[0m' # No Color
29+
30+
print_header() {
31+
echo -e "${BLUE}======================================${NC}"
32+
echo -e "${BLUE} Generals Game Code - Linux Builder${NC}"
33+
echo -e "${BLUE}======================================${NC}"
34+
echo ""
35+
}
36+
37+
print_success() {
38+
echo -e "${GREEN}[SUCCESS]${NC} $1"
39+
}
40+
41+
print_warning() {
42+
echo -e "${YELLOW}[WARNING]${NC} $1"
43+
}
44+
45+
print_error() {
46+
echo -e "${RED}[ERROR]${NC} $1"
47+
}
48+
49+
print_info() {
50+
echo -e "${BLUE}[INFO]${NC} $1"
51+
}
52+
53+
usage() {
54+
cat <<EOF
55+
Usage: $(basename "$0") [OPTIONS] [TARGET...]
56+
57+
Build Generals/Zero Hour on Linux using Docker (produces Windows executables).
58+
59+
Options:
60+
-h, --help Show this help message
61+
-g, --game GAME Build specific game: 'zh' (Zero Hour), 'generals', or 'all' (default: all)
62+
-t, --target TARGET Build specific CMake target (e.g., generalszh, WorldBuilderZH)
63+
-c, --clean Clean build directory before building
64+
-i, --interactive Enter container shell for debugging
65+
--cmake Force CMake reconfiguration
66+
-j, --jobs N Number of parallel jobs (passed to ninja)
67+
68+
Examples:
69+
$(basename "$0") # Build everything
70+
$(basename "$0") --game zh # Build Zero Hour only
71+
$(basename "$0") --target generalszh # Build Zero Hour executable only
72+
$(basename "$0") --clean --game all # Clean and rebuild everything
73+
$(basename "$0") --interactive # Enter container for debugging
74+
75+
Output:
76+
Build artifacts are placed in: $BUILD_DIR/
77+
78+
Zero Hour executables:
79+
- generalszh.exe (Main game)
80+
- WorldBuilderZH.exe (Map editor)
81+
- W3DViewZH.exe (3D model viewer)
82+
83+
Generals executables:
84+
- generalsv.exe (Main game)
85+
- WorldBuilderV.exe (Map editor)
86+
- W3DViewV.exe (3D model viewer)
87+
88+
Running the game:
89+
After building, you can run the game with Wine:
90+
wine $BUILD_DIR/GeneralsMD/generalszh.exe
91+
92+
Note: You need the original game data files installed.
93+
EOF
94+
}
95+
96+
check_dependencies() {
97+
print_info "Checking dependencies..."
98+
99+
if ! command -v docker &>/dev/null; then
100+
print_error "Docker is not installed. Please install Docker first."
101+
echo " See: https://docs.docker.com/engine/install/"
102+
exit 1
103+
fi
104+
105+
if ! docker info &>/dev/null; then
106+
print_error "Docker daemon is not running or you don't have permission."
107+
echo " Try: sudo systemctl start docker"
108+
echo " Or add your user to the docker group: sudo usermod -aG docker \$USER"
109+
exit 1
110+
fi
111+
112+
print_success "All dependencies satisfied"
113+
}
114+
115+
build_docker_image() {
116+
print_info "Building Docker image (this may take a while on first run)..."
117+
118+
docker build \
119+
--build-arg UID="$(id -u)" \
120+
--build-arg GID="$(id -g)" \
121+
"$PROJECT_DIR/resources/dockerbuild" \
122+
-t zerohour-build \
123+
|| {
124+
print_error "Failed to build Docker image"
125+
exit 1
126+
}
127+
128+
print_success "Docker image ready"
129+
}
130+
131+
run_build() {
132+
local force_cmake="$1"
133+
local target="$2"
134+
local interactive="$3"
135+
136+
local docker_flags=""
137+
if [[ "$interactive" == "true" ]]; then
138+
docker_flags="-it --entrypoint bash"
139+
fi
140+
141+
print_info "Starting build..."
142+
if [[ -n "$target" ]]; then
143+
print_info "Target: $target"
144+
fi
145+
146+
# shellcheck disable=SC2086
147+
docker run \
148+
-u "$(id -u):$(id -g)" \
149+
-e MAKE_TARGET="$target" \
150+
-e FORCE_CMAKE="$force_cmake" \
151+
-v "$PROJECT_DIR:/build/cnc" \
152+
--rm \
153+
$docker_flags \
154+
zerohour-build \
155+
|| {
156+
print_error "Build failed"
157+
exit 1
158+
}
159+
160+
if [[ "$interactive" != "true" ]]; then
161+
print_success "Build completed"
162+
fi
163+
}
164+
165+
clean_build() {
166+
print_info "Cleaning build directory..."
167+
rm -rf "$BUILD_DIR"
168+
print_success "Build directory cleaned"
169+
}
170+
171+
list_outputs() {
172+
echo ""
173+
print_info "Build outputs:"
174+
echo ""
175+
176+
if [[ -d "$BUILD_DIR/GeneralsMD" ]]; then
177+
echo "Zero Hour (GeneralsMD):"
178+
find "$BUILD_DIR/GeneralsMD" -maxdepth 1 -name "*.exe" -printf " %f (%s bytes)\n" 2>/dev/null || true
179+
fi
180+
181+
if [[ -d "$BUILD_DIR/Generals" ]]; then
182+
echo ""
183+
echo "Generals:"
184+
find "$BUILD_DIR/Generals" -maxdepth 1 -name "*.exe" -printf " %f (%s bytes)\n" 2>/dev/null || true
185+
fi
186+
}
187+
188+
# Parse arguments
189+
GAME="all"
190+
TARGET=""
191+
CLEAN=false
192+
INTERACTIVE=false
193+
FORCE_CMAKE=false
194+
195+
while [[ $# -gt 0 ]]; do
196+
case "$1" in
197+
-h|--help)
198+
usage
199+
exit 0
200+
;;
201+
-g|--game)
202+
GAME="$2"
203+
shift 2
204+
;;
205+
-t|--target)
206+
TARGET="$2"
207+
shift 2
208+
;;
209+
-c|--clean)
210+
CLEAN=true
211+
shift
212+
;;
213+
-i|--interactive)
214+
INTERACTIVE=true
215+
shift
216+
;;
217+
--cmake)
218+
FORCE_CMAKE=true
219+
shift
220+
;;
221+
-j|--jobs)
222+
# Jobs are handled by ninja in the container
223+
shift 2
224+
;;
225+
-*)
226+
print_error "Unknown option: $1"
227+
usage
228+
exit 1
229+
;;
230+
*)
231+
# Positional argument treated as target
232+
TARGET="$TARGET $1"
233+
shift
234+
;;
235+
esac
236+
done
237+
238+
# Set target based on game selection
239+
if [[ -z "$TARGET" ]]; then
240+
case "$GAME" in
241+
zh|zerohour)
242+
TARGET="generalszh generalszh_tools"
243+
;;
244+
generals)
245+
TARGET="generalsv generalsv_tools"
246+
;;
247+
all)
248+
TARGET="" # Build all
249+
;;
250+
*)
251+
print_error "Unknown game: $GAME (use 'zh', 'generals', or 'all')"
252+
exit 1
253+
;;
254+
esac
255+
fi
256+
257+
# Main execution
258+
print_header
259+
check_dependencies
260+
261+
if [[ "$CLEAN" == "true" ]]; then
262+
clean_build
263+
fi
264+
265+
build_docker_image
266+
run_build "$FORCE_CMAKE" "$TARGET" "$INTERACTIVE"
267+
268+
if [[ "$INTERACTIVE" != "true" ]]; then
269+
list_outputs
270+
271+
echo ""
272+
print_info "To run the game with Wine:"
273+
echo " wine $BUILD_DIR/GeneralsMD/generalszh.exe"
274+
fi

0 commit comments

Comments
 (0)