-
-
Notifications
You must be signed in to change notification settings - Fork 19
Expand file tree
/
Copy pathMakefile
More file actions
596 lines (529 loc) · 24.8 KB
/
Copy pathMakefile
File metadata and controls
596 lines (529 loc) · 24.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
# ionclaw build system
# run make help for the list of targets
.DEFAULT_GOAL := help
# --- directories ---
BUILD_DIR := build/release
BUILD_DEBUG_DIR := build/debug
BUILD_SHARED_DIR := build/shared
BUILD_IOS_ARM64 := build/ios-arm64
BUILD_IOS_SIM_ARM64 := build/ios-sim-arm64
BUILD_IOS_SIM_X86 := build/ios-sim-x86_64
BUILD_TVOS_ARM64 := build/tvos-arm64
BUILD_TVOS_SIM_ARM64 := build/tvos-sim-arm64
BUILD_TVOS_SIM_X86 := build/tvos-sim-x86_64
BUILD_WATCHOS_ARM64 := build/watchos-arm64
BUILD_WATCHOS_ARM64_32 := build/watchos-arm64_32
BUILD_WATCHOS_ARM64_64 := build/watchos-arm64-64
BUILD_WATCHOS_SIM_ARM64 := build/watchos-sim-arm64
BUILD_WATCHOS_SIM_X86 := build/watchos-sim-x86_64
BUILD_XCFRAMEWORK := build/xcframework
APPLE_APP_DIR := apps/apple
BUILD_ANDROID_ARM64 := build/android-arm64-v8a
BUILD_ANDROID_X86_64 := build/android-x86_64
BUILD_ANDROID_X86 := build/android-x86
WEB_SRC_DIR := apps/web
WEB_OUT_DIR := main/resources/web
FLUTTER_PLUGIN_DIR := apps/flutter/plugin
FLUTTER_RUNNER_DIR := apps/flutter/runner
ANDROID_APP_DIR := apps/android/app
ANDROID_LIB_DIR := apps/android/library
ANDROID_AAR_JNILIBS := $(ANDROID_LIB_DIR)/src/main/jniLibs
BUILD_ANDROID_AAR := build/android-aar
# --- cmake flags ---
CMAKE_FLAGS := -DCMAKE_BUILD_TYPE=Release
CMAKE_DEBUG_FLAGS := -DCMAKE_BUILD_TYPE=Debug
CMAKE_SHARED_FLAGS := $(CMAKE_FLAGS) -DIONCLAW_BUILD_SHARED=ON
# --- android toolchain ---
ANDROID_NDK ?= $(ANDROID_NDK_ROOT)
ANDROID_API := 24
ANDROID_TOOLCHAIN = $(ANDROID_NDK)/build/cmake/android.toolchain.cmake
ANDROID_ABIS := arm64-v8a x86_64 x86
# --- helpers ---
NPROC := $(shell nproc 2>/dev/null || sysctl -n hw.ncpu)
# help
.PHONY: help
help:
@echo ""
@echo "IonClaw Build System"
@echo "===================="
@echo ""
@echo "Build:"
@echo " make build Build server executable (release)"
@echo " make build-debug Build server executable (debug)"
@echo " make install Build and install to /usr/local/bin (symlink)"
@echo " make uninstall Remove installed symlink"
@echo " make build-web Build web client (Vue.js)"
@echo " make build-lib Build shared library (macOS/Linux)"
@echo " make build-xcframework Build XCFramework (iOS + tvOS + watchOS)"
@echo " make build-android Build Android .so for all ABIs"
@echo " make build-android-aar Assemble the standalone ionclaw aar for distribution"
@echo " make build-all Build everything (server + web + shared lib)"
@echo " make build-apple Build all Apple targets (macOS + iOS)"
@echo " make build-docker Build Docker image"
@echo ""
@echo "Run:"
@echo " make run Build and run server (release)"
@echo " make run-debug Build and run server (debug)"
@echo " make run-web Run web client dev server (Vite HMR)"
@echo " make run-docker Build and run Docker container"
@echo " make run-flutter Build and run Flutter app (device picker)"
@echo " make run-flutter-release Build and run Flutter app (release, device picker)"
@echo " make run-flutter-macos Build and run Flutter app (macOS)"
@echo " make run-android Build, install and launch the native Android app"
@echo ""
@echo "Release:"
@echo " make release-macos Build macOS app"
@echo " make android-gen-key Generate Android upload keystore and certificate"
@echo ""
@echo "Setup:"
@echo " make setup-web Install web client npm dependencies"
@echo " make flutter-deps Install and upgrade Flutter dependencies"
@echo " make prepare-flutter-macos Build macOS dylib + web (if not present)"
@echo " make prepare-apple Build XCFramework + generate Apple Xcode project"
@echo " make gen-apple Generate Apple Xcode project (XcodeGen)"
@echo " make prepare-android Build Android .so for the aar library (if not present)"
@echo " make link-android Force rebuild Android .so files into the aar library"
@echo " make link-flutter-macos Force rebuild macOS dylib to Flutter plugin"
@echo " make link-flutter-web Force rebuild web client to Flutter plugin"
@echo ""
@echo "Clean:"
@echo " make clean Remove all build directories"
@echo " make clean-build Remove server build directories"
@echo " make clean-web Remove web client build output"
@echo " make clean-lib Remove shared library build"
@echo " make clean-ios Remove iOS/XCFramework builds"
@echo " make clean-android Remove Android builds and jniLibs"
@echo ""
@echo "Version:"
@echo " make version V=1.0.0+2 Set version (all files) with optional build number"
@echo ""
@echo "Code:"
@echo " make format Format all C/C++/ObjC sources with clang-format"
@echo ""
@echo "Options:"
@echo " ARGS=\"...\" Extra arguments passed to the server binary"
@echo " ANDROID_NDK=\"...\" Android NDK root (defaults to ANDROID_NDK_ROOT)"
@echo ""
@echo "Examples:"
@echo " make run ARGS=\"--project /path/to/project --port 9090\""
@echo " make build-android ANDROID_NDK=/path/to/ndk"
@echo ""
# build
.PHONY: build
build: ## Build server executable (release)
@echo "==> Building server (release)..."
cmake -B $(BUILD_DIR) $(CMAKE_FLAGS)
cmake --build $(BUILD_DIR) -j$(NPROC)
@echo "==> Done: $(BUILD_DIR)/bin/ionclaw-server"
.PHONY: test
test: ## Build and run the unit test suite
@echo "==> Building tests..."
cmake -B $(BUILD_DIR) $(CMAKE_FLAGS) -DIONCLAW_BUILD_TESTS=ON
cmake --build $(BUILD_DIR) --target ionclaw-tests -j$(NPROC)
@echo "==> Running tests..."
ctest --test-dir $(BUILD_DIR) --output-on-failure
.PHONY: build-debug
build-debug: ## Build server executable (debug)
@echo "==> Building server (debug)..."
cmake -B $(BUILD_DEBUG_DIR) $(CMAKE_DEBUG_FLAGS)
cmake --build $(BUILD_DEBUG_DIR) -j$(NPROC)
@echo "==> Done: $(BUILD_DEBUG_DIR)/bin/ionclaw-server"
# --- install directories ---
ifeq ($(OS),Windows_NT)
INSTALL_DIR ?= $(USERPROFILE)\bin
BINARY_NAME := ionclaw-server.exe
BUILT_BINARY := $(BUILD_DIR)/bin/Release/$(BINARY_NAME)
else
INSTALL_DIR ?= $(HOME)/.local/bin
BINARY_NAME := ionclaw-server
BUILT_BINARY := $(shell pwd)/$(BUILD_DIR)/bin/$(BINARY_NAME)
endif
.PHONY: install
install: build ## Build and install ionclaw-server to INSTALL_DIR (default: ~/.local/bin)
ifeq ($(OS),Windows_NT)
@echo "==> Installing to $(INSTALL_DIR)..."
@if not exist "$(INSTALL_DIR)" mkdir "$(INSTALL_DIR)"
copy /Y "$(BUILT_BINARY)" "$(INSTALL_DIR)\$(BINARY_NAME)"
@echo "==> Installed: $(INSTALL_DIR)\$(BINARY_NAME)"
@echo " Make sure $(INSTALL_DIR) is in your PATH."
else
@mkdir -p $(INSTALL_DIR)
@echo "==> Installing symlink to $(INSTALL_DIR)/$(BINARY_NAME)..."
ln -sf $(BUILT_BINARY) $(INSTALL_DIR)/$(BINARY_NAME)
@echo "==> Installed: $(INSTALL_DIR)/$(BINARY_NAME) -> $(BUILT_BINARY)"
@if ! echo "$$PATH" | grep -q "$(INSTALL_DIR)"; then \
echo " NOTE: Add $(INSTALL_DIR) to your PATH if not already:"; \
echo " export PATH=\"$(INSTALL_DIR):\$$PATH\""; \
fi
endif
.PHONY: uninstall
uninstall: ## Remove installed ionclaw-server from INSTALL_DIR
ifeq ($(OS),Windows_NT)
@echo "==> Removing $(INSTALL_DIR)\$(BINARY_NAME)..."
@if exist "$(INSTALL_DIR)\$(BINARY_NAME)" del "$(INSTALL_DIR)\$(BINARY_NAME)"
else
@echo "==> Removing $(INSTALL_DIR)/$(BINARY_NAME)..."
rm -f $(INSTALL_DIR)/$(BINARY_NAME)
endif
@echo "==> Uninstalled."
.PHONY: build-web
build-web: ## Build web client (Vue.js → main/resources/web/)
@echo "==> Building web client..."
cd $(WEB_SRC_DIR) && npm run build
@echo "==> Done: $(WEB_OUT_DIR)/"
.PHONY: build-lib
build-lib: ## Build shared library for FFI (libionclaw.dylib/.so)
@echo "==> Building shared library..."
cmake -B $(BUILD_SHARED_DIR) $(CMAKE_SHARED_FLAGS)
cmake --build $(BUILD_SHARED_DIR) -j$(NPROC)
@echo "==> Done: $(BUILD_SHARED_DIR)/lib/"
.PHONY: build-ios-arm64
build-ios-arm64: ## Build iOS arm64 shared library
@echo "==> Building iOS arm64..."
cmake -B $(BUILD_IOS_ARM64) $(CMAKE_SHARED_FLAGS) \
-DCMAKE_SYSTEM_NAME=iOS \
-DCMAKE_OSX_ARCHITECTURES=arm64 \
-DCMAKE_OSX_SYSROOT=iphoneos
cmake --build $(BUILD_IOS_ARM64) -j$(NPROC)
@echo "==> Done: $(BUILD_IOS_ARM64)/lib/"
.PHONY: build-ios-sim-arm64
build-ios-sim-arm64: ## Build iOS simulator arm64 shared library
@echo "==> Building iOS simulator arm64..."
cmake -B $(BUILD_IOS_SIM_ARM64) $(CMAKE_SHARED_FLAGS) \
-DCMAKE_SYSTEM_NAME=iOS \
-DCMAKE_OSX_ARCHITECTURES=arm64 \
-DCMAKE_OSX_SYSROOT=iphonesimulator
cmake --build $(BUILD_IOS_SIM_ARM64) -j$(NPROC)
@echo "==> Done: $(BUILD_IOS_SIM_ARM64)/lib/"
.PHONY: build-ios-sim-x86
build-ios-sim-x86: ## Build iOS simulator x86_64 shared library
@echo "==> Building iOS simulator x86_64..."
cmake -B $(BUILD_IOS_SIM_X86) $(CMAKE_SHARED_FLAGS) \
-DCMAKE_SYSTEM_NAME=iOS \
-DCMAKE_OSX_ARCHITECTURES=x86_64 \
-DCMAKE_OSX_SYSROOT=iphonesimulator
cmake --build $(BUILD_IOS_SIM_X86) -j$(NPROC)
@echo "==> Done: $(BUILD_IOS_SIM_X86)/lib/"
.PHONY: build-tvos-arm64
build-tvos-arm64: ## Build tvOS arm64 shared library
@echo "==> Building tvOS arm64..."
cmake -B $(BUILD_TVOS_ARM64) $(CMAKE_SHARED_FLAGS) \
-DCMAKE_SYSTEM_NAME=tvOS \
-DCMAKE_OSX_ARCHITECTURES=arm64 \
-DCMAKE_OSX_SYSROOT=appletvos
cmake --build $(BUILD_TVOS_ARM64) -j$(NPROC)
@echo "==> Done: $(BUILD_TVOS_ARM64)/lib/"
.PHONY: build-tvos-sim-arm64
build-tvos-sim-arm64: ## Build tvOS simulator arm64 shared library
@echo "==> Building tvOS simulator arm64..."
cmake -B $(BUILD_TVOS_SIM_ARM64) $(CMAKE_SHARED_FLAGS) \
-DCMAKE_SYSTEM_NAME=tvOS \
-DCMAKE_OSX_ARCHITECTURES=arm64 \
-DCMAKE_OSX_SYSROOT=appletvsimulator
cmake --build $(BUILD_TVOS_SIM_ARM64) -j$(NPROC)
@echo "==> Done: $(BUILD_TVOS_SIM_ARM64)/lib/"
.PHONY: build-tvos-sim-x86
build-tvos-sim-x86: ## Build tvOS simulator x86_64 shared library
@echo "==> Building tvOS simulator x86_64..."
cmake -B $(BUILD_TVOS_SIM_X86) $(CMAKE_SHARED_FLAGS) \
-DCMAKE_SYSTEM_NAME=tvOS \
-DCMAKE_OSX_ARCHITECTURES=x86_64 \
-DCMAKE_OSX_SYSROOT=appletvsimulator
cmake --build $(BUILD_TVOS_SIM_X86) -j$(NPROC)
@echo "==> Done: $(BUILD_TVOS_SIM_X86)/lib/"
.PHONY: build-watchos-arm64
build-watchos-arm64: ## Build watchOS device shared library (arm64_32 + arm64)
@echo "==> Building watchOS device arm64_32..."
cmake -B $(BUILD_WATCHOS_ARM64_32) $(CMAKE_SHARED_FLAGS) \
-DCMAKE_SYSTEM_NAME=watchOS \
-DCMAKE_OSX_ARCHITECTURES=arm64_32 \
-DCMAKE_OSX_SYSROOT=watchos
cmake --build $(BUILD_WATCHOS_ARM64_32) -j$(NPROC)
@echo "==> Building watchOS device arm64..."
cmake -B $(BUILD_WATCHOS_ARM64_64) $(CMAKE_SHARED_FLAGS) \
-DCMAKE_SYSTEM_NAME=watchOS \
-DCMAKE_OSX_ARCHITECTURES=arm64 \
-DCMAKE_OSX_SYSROOT=watchos
cmake --build $(BUILD_WATCHOS_ARM64_64) -j$(NPROC)
@echo "==> Creating watchOS device fat framework (arm64_32 + arm64)..."
rm -rf $(BUILD_WATCHOS_ARM64)/lib/ionclaw.framework
mkdir -p $(BUILD_WATCHOS_ARM64)/lib
cp -R $(BUILD_WATCHOS_ARM64_32)/lib/ionclaw.framework $(BUILD_WATCHOS_ARM64)/lib/ionclaw.framework
lipo -create \
$(BUILD_WATCHOS_ARM64_32)/lib/ionclaw.framework/ionclaw \
$(BUILD_WATCHOS_ARM64_64)/lib/ionclaw.framework/ionclaw \
-output $(BUILD_WATCHOS_ARM64)/lib/ionclaw.framework/ionclaw
@echo "==> Done: $(BUILD_WATCHOS_ARM64)/lib/"
.PHONY: build-watchos-sim-arm64
build-watchos-sim-arm64: ## Build watchOS simulator arm64 shared library
@echo "==> Building watchOS simulator arm64..."
cmake -B $(BUILD_WATCHOS_SIM_ARM64) $(CMAKE_SHARED_FLAGS) \
-DCMAKE_SYSTEM_NAME=watchOS \
-DCMAKE_OSX_ARCHITECTURES=arm64 \
-DCMAKE_OSX_SYSROOT=watchsimulator
cmake --build $(BUILD_WATCHOS_SIM_ARM64) -j$(NPROC)
@echo "==> Done: $(BUILD_WATCHOS_SIM_ARM64)/lib/"
.PHONY: build-watchos-sim-x86
build-watchos-sim-x86: ## Build watchOS simulator x86_64 shared library
@echo "==> Building watchOS simulator x86_64..."
cmake -B $(BUILD_WATCHOS_SIM_X86) $(CMAKE_SHARED_FLAGS) \
-DCMAKE_SYSTEM_NAME=watchOS \
-DCMAKE_OSX_ARCHITECTURES=x86_64 \
-DCMAKE_OSX_SYSROOT=watchsimulator
cmake --build $(BUILD_WATCHOS_SIM_X86) -j$(NPROC)
@echo "==> Done: $(BUILD_WATCHOS_SIM_X86)/lib/"
.PHONY: build-xcframework
build-xcframework: build-ios-arm64 build-ios-sim-arm64 build-ios-sim-x86 build-tvos-arm64 build-tvos-sim-arm64 build-tvos-sim-x86 build-watchos-arm64 build-watchos-sim-arm64 build-watchos-sim-x86 ## Build XCFramework (iOS + tvOS + watchOS)
@echo "==> Creating iOS simulator fat framework..."
mkdir -p $(BUILD_XCFRAMEWORK)/ios-sim/ionclaw.framework
lipo -create \
$(BUILD_IOS_SIM_ARM64)/lib/ionclaw.framework/ionclaw \
$(BUILD_IOS_SIM_X86)/lib/ionclaw.framework/ionclaw \
-output $(BUILD_XCFRAMEWORK)/ios-sim/ionclaw.framework/ionclaw
cp $(BUILD_IOS_SIM_ARM64)/lib/ionclaw.framework/Info.plist $(BUILD_XCFRAMEWORK)/ios-sim/ionclaw.framework/
@echo "==> Creating tvOS simulator fat framework..."
mkdir -p $(BUILD_XCFRAMEWORK)/tvos-sim/ionclaw.framework
lipo -create \
$(BUILD_TVOS_SIM_ARM64)/lib/ionclaw.framework/ionclaw \
$(BUILD_TVOS_SIM_X86)/lib/ionclaw.framework/ionclaw \
-output $(BUILD_XCFRAMEWORK)/tvos-sim/ionclaw.framework/ionclaw
cp $(BUILD_TVOS_SIM_ARM64)/lib/ionclaw.framework/Info.plist $(BUILD_XCFRAMEWORK)/tvos-sim/ionclaw.framework/
@echo "==> Creating watchOS simulator fat framework..."
mkdir -p $(BUILD_XCFRAMEWORK)/watchos-sim/ionclaw.framework
lipo -create \
$(BUILD_WATCHOS_SIM_ARM64)/lib/ionclaw.framework/ionclaw \
$(BUILD_WATCHOS_SIM_X86)/lib/ionclaw.framework/ionclaw \
-output $(BUILD_XCFRAMEWORK)/watchos-sim/ionclaw.framework/ionclaw
cp $(BUILD_WATCHOS_SIM_ARM64)/lib/ionclaw.framework/Info.plist $(BUILD_XCFRAMEWORK)/watchos-sim/ionclaw.framework/
@echo "==> Creating XCFramework..."
rm -rf $(BUILD_XCFRAMEWORK)/ionclaw.xcframework
xcodebuild -create-xcframework \
-framework $(BUILD_IOS_ARM64)/lib/ionclaw.framework \
-framework $(BUILD_XCFRAMEWORK)/ios-sim/ionclaw.framework \
-framework $(BUILD_TVOS_ARM64)/lib/ionclaw.framework \
-framework $(BUILD_XCFRAMEWORK)/tvos-sim/ionclaw.framework \
-framework $(BUILD_WATCHOS_ARM64)/lib/ionclaw.framework \
-framework $(BUILD_XCFRAMEWORK)/watchos-sim/ionclaw.framework \
-output $(BUILD_XCFRAMEWORK)/ionclaw.xcframework
@echo "==> Done: $(BUILD_XCFRAMEWORK)/ionclaw.xcframework"
.PHONY: build-android-arm64
build-android-arm64: ## Build Android arm64-v8a shared library
@echo "==> Building Android arm64-v8a..."
cmake -B $(BUILD_ANDROID_ARM64) $(CMAKE_SHARED_FLAGS) \
-DCMAKE_TOOLCHAIN_FILE=$(ANDROID_TOOLCHAIN) \
-DANDROID_ABI=arm64-v8a \
-DANDROID_PLATFORM=android-$(ANDROID_API) \
-DANDROID_STL=c++_static
cmake --build $(BUILD_ANDROID_ARM64) -j$(NPROC)
@echo "==> Done: $(BUILD_ANDROID_ARM64)/lib/"
.PHONY: build-android-x86_64
build-android-x86_64: ## Build Android x86_64 shared library
@echo "==> Building Android x86_64..."
cmake -B $(BUILD_ANDROID_X86_64) $(CMAKE_SHARED_FLAGS) \
-DCMAKE_TOOLCHAIN_FILE=$(ANDROID_TOOLCHAIN) \
-DANDROID_ABI=x86_64 \
-DANDROID_PLATFORM=android-$(ANDROID_API) \
-DANDROID_STL=c++_static
cmake --build $(BUILD_ANDROID_X86_64) -j$(NPROC)
@echo "==> Done: $(BUILD_ANDROID_X86_64)/lib/"
.PHONY: build-android-x86
build-android-x86: ## Build Android x86 shared library
@echo "==> Building Android x86..."
cmake -B $(BUILD_ANDROID_X86) $(CMAKE_SHARED_FLAGS) \
-DCMAKE_TOOLCHAIN_FILE=$(ANDROID_TOOLCHAIN) \
-DANDROID_ABI=x86 \
-DANDROID_PLATFORM=android-$(ANDROID_API) \
-DANDROID_STL=c++_static
cmake --build $(BUILD_ANDROID_X86) -j$(NPROC)
@echo "==> Done: $(BUILD_ANDROID_X86)/lib/"
.PHONY: build-android
build-android: build-android-arm64 build-android-x86_64 build-android-x86 ## Build Android shared libraries for all ABIs
@echo "==> All Android ABIs built."
.PHONY: build-all
build-all: build-web build build-lib ## Build everything (web + server + shared lib)
@echo "==> All targets built."
.PHONY: build-apple
build-apple: build-lib build-xcframework ## Build all Apple targets
@echo "==> All Apple targets built."
.PHONY: build-docker
build-docker: ## Build Docker image
@echo "==> Building Docker image..."
docker build -t ionclaw .
@echo "==> Done: docker image 'ionclaw'"
# run
.PHONY: run
run: build ## Build and run server (release)
@echo "==> Starting server..."
$(BUILD_DIR)/bin/ionclaw-server $(ARGS)
.PHONY: run-debug
run-debug: build-debug ## Build and run server (debug)
@echo "==> Starting server (debug)..."
$(BUILD_DEBUG_DIR)/bin/ionclaw-server --debug $(ARGS)
.PHONY: run-web
run-web: ## Run web client dev server (Vite HMR)
cd $(WEB_SRC_DIR) && npm run dev
.PHONY: run-docker
run-docker: build-docker ## Build and run Docker container
@echo "==> Running Docker container..."
docker run -p 8080:8080 -e PORT=8080 ionclaw
.PHONY: run-flutter
run-flutter: prepare-flutter-macos ## Build (if needed) and run Flutter app (device picker)
@echo "==> Running Flutter app..."
cd $(FLUTTER_RUNNER_DIR) && flutter run
.PHONY: run-flutter-release
run-flutter-release: prepare-flutter-macos ## Build (if needed) and run Flutter app (release, device picker)
@echo "==> Running Flutter app (release)..."
cd $(FLUTTER_RUNNER_DIR) && flutter run --release
.PHONY: run-flutter-macos
run-flutter-macos: prepare-flutter-macos ## Build (if needed) and run Flutter app (macOS)
@echo "==> Running Flutter app (macOS)..."
cd $(FLUTTER_RUNNER_DIR) && flutter run -d macos
.PHONY: run-android
run-android: build-android-aar ## Build (if needed), install and launch the native Android app
@echo "==> Building and installing native Android app..."
cd $(ANDROID_APP_DIR) && ./gradlew installDebug
adb shell am start -n com.ionclaw.app/.MainActivity
@echo "==> Done."
# setup
.PHONY: setup-web
setup-web: ## Install web client npm dependencies
@echo "==> Installing web dependencies..."
cd $(WEB_SRC_DIR) && npm install
.PHONY: prepare-flutter-macos
prepare-flutter-macos: ## Build macOS dylib + web client only if not present
@if [ ! -f "$(BUILD_SHARED_DIR)/lib/libionclaw.dylib" ]; then $(MAKE) link-flutter-macos; \
else echo "==> macOS dylib already built (skip). Use 'make clean-lib link-flutter-macos' to rebuild."; fi
@if [ ! -d "$(WEB_OUT_DIR)" ]; then $(MAKE) link-flutter-web; \
else echo "==> Web client already built (skip). Use 'make clean-web link-flutter-web' to rebuild."; fi
.PHONY: gen-apple
gen-apple: ## Generate the Apple (iOS/tvOS/watchOS) Xcode project via XcodeGen
@echo "==> Generating Apple Xcode project..."
cd $(APPLE_APP_DIR) && xcodegen generate
@echo "==> Done: $(APPLE_APP_DIR)/IonClaw.xcodeproj"
.PHONY: prepare-apple
prepare-apple: ## Build XCFramework (if not present) and generate the Apple Xcode project
@if [ ! -d "$(BUILD_XCFRAMEWORK)/ionclaw.xcframework" ]; then $(MAKE) build-xcframework; \
else echo "==> XCFramework already built (skip). Use 'make clean-ios build-xcframework' to rebuild."; fi
@$(MAKE) gen-apple
.PHONY: prepare-android
prepare-android: ## Build Android .so files for the native app only if not present
@if [ ! -d "$(ANDROID_AAR_JNILIBS)/arm64-v8a" ]; then $(MAKE) link-android; \
else echo "==> Android libraries already built (skip). Use 'make clean-android link-android' to rebuild."; fi
.PHONY: build-android-aar
build-android-aar: prepare-android ## Assemble the standalone ionclaw aar for distribution
@echo "==> Assembling ionclaw aar..."
cd $(ANDROID_LIB_DIR) && ./gradlew assembleRelease
mkdir -p $(BUILD_ANDROID_AAR)
cp $(ANDROID_LIB_DIR)/build/outputs/aar/ionclaw-release.aar $(BUILD_ANDROID_AAR)/ionclaw.aar
@echo "==> Done: $(BUILD_ANDROID_AAR)/ionclaw.aar"
.PHONY: link-flutter-macos
link-flutter-macos: build-lib ## Symlink macOS dylib to Flutter plugin
@echo "==> Linking macOS dylib to Flutter plugin..."
ln -sf $$(pwd)/$(BUILD_SHARED_DIR)/lib/libionclaw.dylib $(FLUTTER_PLUGIN_DIR)/macos/libionclaw.dylib
@echo "==> Done: $(FLUTTER_PLUGIN_DIR)/macos/libionclaw.dylib"
.PHONY: link-flutter-web
link-flutter-web: build-web ## Symlink web client to Flutter plugin for bundling
@echo "==> Linking web client to Flutter plugin..."
ln -sf $$(pwd)/$(WEB_OUT_DIR) $(FLUTTER_PLUGIN_DIR)/macos/web
@echo "==> Done: $(FLUTTER_PLUGIN_DIR)/macos/web"
# the native app ships 64-bit abis only (llama.cpp does not build on 32-bit arm)
.PHONY: link-android
link-android: build-android-arm64 build-android-x86_64 ## Copy Android .so files into the standalone aar library project
@echo "==> Copying Android libraries to the aar library project..."
mkdir -p $(ANDROID_AAR_JNILIBS)/arm64-v8a
mkdir -p $(ANDROID_AAR_JNILIBS)/x86_64
cp $(BUILD_ANDROID_ARM64)/lib/libionclaw.so $(ANDROID_AAR_JNILIBS)/arm64-v8a/
cp $(BUILD_ANDROID_X86_64)/lib/libionclaw.so $(ANDROID_AAR_JNILIBS)/x86_64/
@# the engine links against openmp at runtime, so ship the ndk libomp.so alongside it
cp $$(find $(ANDROID_NDK)/toolchains/llvm/prebuilt -path '*/lib/linux/aarch64/libomp.so' | head -1) $(ANDROID_AAR_JNILIBS)/arm64-v8a/libomp.so
cp $$(find $(ANDROID_NDK)/toolchains/llvm/prebuilt -path '*/lib/linux/x86_64/libomp.so' | head -1) $(ANDROID_AAR_JNILIBS)/x86_64/libomp.so
@echo "==> Done: $(ANDROID_AAR_JNILIBS)/"
# release
.PHONY: release-macos
release-macos: link-flutter-macos link-flutter-web ## Build macOS release
@echo "==> Building macOS release..."
cd $(FLUTTER_RUNNER_DIR) && flutter build macos
@echo "==> Done."
@echo "App: $(FLUTTER_RUNNER_DIR)/build/macos/Build/Products/Release/"
.PHONY: android-gen-key
android-gen-key: ## Generate Android upload keystore and certificate
@if [ -f "extras/android/upload-keystore.jks" ]; then \
echo "==> Keystore already exists: extras/android/upload-keystore.jks (skip)"; \
else \
echo "==> Generating Android upload keystore..."; \
mkdir -p extras/android; \
keytool -genkeypair -v \
-keystore extras/android/upload-keystore.jks \
-storepass upload \
-keypass upload \
-alias upload \
-keyalg RSA -keysize 2048 -validity 10000 \
-dname "CN=Upload, OU=Upload, O=Upload, L=Upload, ST=Upload, C=BR"; \
keytool -export -rfc \
-keystore extras/android/upload-keystore.jks \
-storepass upload \
-alias upload \
-file extras/android/upload-certificate.pem; \
echo "==> Done."; \
echo "Keystore: extras/android/upload-keystore.jks"; \
echo "Certificate: extras/android/upload-certificate.pem"; \
fi
.PHONY: flutter-deps
flutter-deps: ## Install and upgrade Flutter dependencies
cd $(FLUTTER_RUNNER_DIR) && flutter pub get && flutter pub upgrade
# clean
.PHONY: clean
clean: ## Remove all build directories
@echo "==> Cleaning all build directories..."
rm -rf build
@echo "==> Clean complete."
.PHONY: clean-build
clean-build: ## Remove server build directories
rm -rf $(BUILD_DIR) $(BUILD_DEBUG_DIR)
.PHONY: clean-web
clean-web: ## Remove web client build output
rm -rf $(WEB_OUT_DIR)
.PHONY: clean-lib
clean-lib: ## Remove shared library build
rm -rf $(BUILD_SHARED_DIR)
.PHONY: clean-ios
clean-ios: ## Remove iOS/tvOS/watchOS/XCFramework build directories
rm -rf $(BUILD_IOS_ARM64) $(BUILD_IOS_SIM_ARM64) $(BUILD_IOS_SIM_X86) \
$(BUILD_TVOS_ARM64) $(BUILD_TVOS_SIM_ARM64) $(BUILD_TVOS_SIM_X86) \
$(BUILD_WATCHOS_ARM64) $(BUILD_WATCHOS_SIM_ARM64) $(BUILD_WATCHOS_SIM_X86) \
$(BUILD_XCFRAMEWORK)
.PHONY: clean-android
clean-android: ## Remove Android build directories and jniLibs
rm -rf $(BUILD_ANDROID_ARM64) $(BUILD_ANDROID_X86_64) $(BUILD_ANDROID_X86)
rm -rf $(ANDROID_AAR_JNILIBS)
rm -rf $(BUILD_ANDROID_AAR)
# version
.PHONY: version
version: ## Set project version: make version V=1.0.0+2
@if [ -z "$(V)" ]; then \
echo "Usage: make version V=1.0.0+2"; \
echo " Format: MAJOR.MINOR.PATCH+BUILD (build number is optional, default 1)"; \
exit 1; \
fi
@VER=$$(echo "$(V)" | cut -d'+' -f1); \
BUILD=$$(echo "$(V)" | grep -o '+.*' | tr -d '+'); \
if [ -z "$$BUILD" ]; then BUILD=1; fi; \
echo "==> Setting version to $$VER+$$BUILD"; \
SED_INPLACE() { sed "$$1" "$$2" > "$$2.tmp" && mv "$$2.tmp" "$$2"; }; \
SED_INPLACE "s|set(IONCLAW_VERSION \"[^\"]*\"|set(IONCLAW_VERSION \"$$VER\"|" CMakeLists.txt; \
SED_INPLACE "s|^version: [0-9].*|version: $$VER+$$BUILD|" apps/flutter/runner/pubspec.yaml; \
SED_INPLACE "s|^version: [0-9].*|version: $$VER|" apps/flutter/plugin/pubspec.yaml; \
SED_INPLACE "s|\"version\": \"[0-9][^\"]*\"|\"version\": \"$$VER\"|" apps/web/package.json; \
SED_INPLACE "s|const CACHE_NAME = 'ionclaw_[^']*'|const CACHE_NAME = 'ionclaw_$$VER'|" apps/web/public/sw.js; \
echo " CMakeLists.txt → $$VER"; \
echo " flutter/runner/pubspec → $$VER+$$BUILD"; \
echo " flutter/plugin/pubspec → $$VER"; \
echo " web/package.json → $$VER"; \
echo " web/sw.js → $$VER"; \
echo "==> Done."
# code
.PHONY: format
format: ## Format all C/C++/ObjC sources with clang-format
@echo "==> Formatting sources..."
find main -type f \( -name "*.cpp" -o -name "*.hpp" -o -name "*.c" -o -name "*.h" -o -name "*.m" -o -name "*.mm" \) | xargs clang-format -i
@echo "==> Done."