From ff94462d8ac6ef10e38f48f8131c29b56f4baf07 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Tue, 13 Feb 2018 11:55:12 +0100 Subject: [PATCH] Refactor build system The client was built with Meson, the server with Gradle, and were run by a Makefile. Add a Meson script for the server (which delegates to Gradle), and a parent script to build and install both the client and the server to the system, typically with: meson --buildtype release build cd build ninja sudo ninja install In addition, use a separate Makefile to build a "portable" version of the application (where the client expects the server to be in the current directory). Typically: make release-portable cd dist/scrcpy ./scrcpy This is especially useful for Windows builds, which are not "installed". --- Makefile | 74 ++++++++++++++++----------------- app/meson.build | 18 +++++++- app/meson_options.txt | 1 + app/src/config.h.in | 3 ++ app/src/server.c | 17 ++++++-- meson.build | 6 +++ scripts/run-scrcpy.sh | 2 + server/meson.build | 11 +++++ server/scripts/build-wrapper.sh | 19 +++++++++ 9 files changed, 109 insertions(+), 42 deletions(-) create mode 100644 app/meson_options.txt create mode 100644 meson.build create mode 100755 scripts/run-scrcpy.sh create mode 100644 server/meson.build create mode 100755 server/scripts/build-wrapper.sh diff --git a/Makefile b/Makefile index 5646d69b..81bef6d1 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,22 @@ -.PHONY: default release clean build build-app build-server run dist dist-zip sums test +# This makefile provides recipes to build a "portable" version of scrcpy. +# +# Here, "portable" means that the client and server binaries are expected to be +# anywhere, but in the same directory, instead of well-defined separate +# locations (e.g. /usr/bin/scrcpy and /usr/share/scrcpy/scrcpy-server.jar). +# +# In particular, this implies to change the location from where the client push +# the server to the device. +# +# "make release-portable" builds a zip containing the client and the server. +# +# This is a simple Makefile because Meson is not flexible enough to execute some +# arbitrary commands. + +.PHONY: default clean release-portable dist-portable dist-portable-zip sums test check GRADLE ?= ./gradlew -APP_BUILD_DIR := app-build -APP_BUILD_DEBUG_DIR := app-build-debug +PORTABLE_BUILD_DIR := build-portable DIST := dist TARGET_DIR := scrcpy @@ -11,47 +24,28 @@ VERSION := $(shell git describe --tags --always) TARGET := $(TARGET_DIR)-$(VERSION).zip default: - @echo 'You must specify a target. Try: make release' - -release: clean dist-zip sums + @echo 'You must specify a target. Try: make release-portable' clean: $(GRADLE) clean - rm -rf "$(APP_BUILD_DIR)" "$(APP_BUILD_DEBUG_DIR)" "$(DIST)" - -build-app-debug: - [ -d "$(APP_BUILD_DEBUG_DIR)" ] || ( mkdir "$(APP_BUILD_DEBUG_DIR)" && \ - meson app "$(APP_BUILD_DEBUG_DIR)" --buildtype debug ) - ninja -C "$(APP_BUILD_DEBUG_DIR)" - -build-server-debug: - $(GRADLE) assembleDebug - -build-debug: build-app-debug build-server-debug + rm -rf "$(PORTABLE_BUILD_DIR)" "$(DIST)" -run-debug: - SCRCPY_SERVER_JAR=server/build/outputs/apk/debug/server-debug.apk $(APP_BUILD_DEBUG_DIR)/scrcpy $(ARGS) +build-portable: + [ -d "$(PORTABLE_BUILD_DIR)" ] || ( mkdir "$(PORTABLE_BUILD_DIR)" && \ + meson "$(PORTABLE_BUILD_DIR)" \ + --buildtype release --strip -Db_lto=true \ + -Dapp:override_server_jar=scrcpy-server.jar ) + ninja -C "$(PORTABLE_BUILD_DIR)" -build-app: - [ -d "$(APP_BUILD_DIR)" ] || ( mkdir "$(APP_BUILD_DIR)" && \ - meson app "$(APP_BUILD_DIR)" --buildtype release -Db_lto ) - ninja -C "$(APP_BUILD_DIR)" +release-portable: clean dist-portable-zip sums + @echo "Release created in $(DIST)/." -build-server: - $(GRADLE) assembleRelease - -build: build-app build-server - -run: - SCRCPY_SERVER_JAR=server/build/outputs/apk/release/server-release-unsigned.apk $(APP_BUILD_DIR)/scrcpy $(ARGS) - -dist: build +dist-portable: build-portable mkdir -p "$(DIST)/$(TARGET_DIR)" - # no need to sign the APK, we dont "install" it, this is in fact a simple jar - cp server/build/outputs/apk/release/server-release-unsigned.apk "$(DIST)/$(TARGET_DIR)/scrcpy-server.jar" - cp $(APP_BUILD_DIR)/scrcpy "$(DIST)/$(TARGET_DIR)/" + cp "$(PORTABLE_BUILD_DIR)"/server/scrcpy-server.jar "$(DIST)/$(TARGET_DIR)/" + cp "$(PORTABLE_BUILD_DIR)"/app/scrcpy "$(DIST)/$(TARGET_DIR)/" -dist-zip: dist +dist-portable-zip: dist-portable cd "$(DIST)"; \ zip -r "$(TARGET)" "$(TARGET_DIR)" @@ -59,6 +53,10 @@ sums: cd "$(DIST)"; \ sha256sum *.zip > SHA256SUM.txt -test: +test: build-portable $(GRADLE) test - ninja -C "$(APP_BUILD_DIR)" test + ninja -C "$(PORTABLE_BUILD_DIR)" test + +check: build-portable + $(GRADLE) check + ninja -C "$(PORTABLE_BUILD_DIR)" test diff --git a/app/meson.build b/app/meson.build index 31fea04a..6ff484a8 100644 --- a/app/meson.build +++ b/app/meson.build @@ -42,6 +42,22 @@ conf.set('BUILD_DEBUG', get_option('buildtype') == 'debug') # (conf.set_quoted() is not available on old versions of meson) conf.set('SCRCPY_VERSION', '"0.1"') +# the prefix used during configuration (meson --prefix=PREFIX) +conf.set('PREFIX', '"' + get_option('prefix') + '"') + +# the path of the server, which will be appended to the prefix +# ignored if OVERRIDE_SERVER_JAR if defined +# must be consistent with the install_dir in server/meson.build +conf.set('PREFIXED_SERVER_JAR', '"/share/scrcpy/scrcpy-server.jar"') + +# the path of the server to be used "as is" +# this is useful for building a "portable" version (with the server in the same +# directory as the client) +override_server_jar = get_option('override_server_jar') +if override_server_jar != '' + conf.set('OVERRIDE_SERVER_JAR', '"' + override_server_jar + '"') +endif + # the default client TCP port for the "adb reverse" tunnel # overridden by option --port conf.set('DEFAULT_LOCAL_PORT', '27183') @@ -61,7 +77,7 @@ conf.set('SKIP_FRAMES', true) configure_file(configuration: conf, input: 'src/config.h.in', output: 'config.h') -executable('scrcpy', src, dependencies: dependencies) +executable('scrcpy', src, dependencies: dependencies, install: true) ### TESTS diff --git a/app/meson_options.txt b/app/meson_options.txt new file mode 100644 index 00000000..1e2768e5 --- /dev/null +++ b/app/meson_options.txt @@ -0,0 +1 @@ +option('override_server_jar', type: 'string') diff --git a/app/src/config.h.in b/app/src/config.h.in index cb8ea5f0..f2c439b8 100644 --- a/app/src/config.h.in +++ b/app/src/config.h.in @@ -1,5 +1,8 @@ #mesondefine BUILD_DEBUG #mesondefine SCRCPY_VERSION +#mesondefine PREFIX +#mesondefine PREFIXED_SERVER_JAR +#mesondefine OVERRIDE_SERVER_JAR #mesondefine DEFAULT_LOCAL_PORT #mesondefine DEFAULT_MAX_SIZE #mesondefine DEFAULT_BIT_RATE diff --git a/app/src/server.c b/app/src/server.c index 333285f9..614f78d7 100644 --- a/app/src/server.c +++ b/app/src/server.c @@ -4,17 +4,28 @@ #include #include +#include "config.h" #include "log.h" #include "netutil.h" #define SOCKET_NAME "scrcpy" -static SDL_bool push_server(const char *serial) { +#ifdef OVERRIDE_SERVER_JAR +# define DEFAULT_SERVER_JAR OVERRIDE_SERVER_JAR +#else +# define DEFAULT_SERVER_JAR PREFIX PREFIXED_SERVER_JAR +#endif + +static const char *get_server_path(void) { const char *server_path = getenv("SCRCPY_SERVER_JAR"); if (!server_path) { - server_path = "scrcpy-server.jar"; + server_path = DEFAULT_SERVER_JAR; } - process_t process = adb_push(serial, server_path, "/data/local/tmp/scrcpy-server.jar"); + return server_path; +} + +static SDL_bool push_server(const char *serial) { + process_t process = adb_push(serial, get_server_path(), "/data/local/tmp/scrcpy-server.jar"); return process_check_success(process, "adb push"); } diff --git a/meson.build b/meson.build new file mode 100644 index 00000000..eb94df9c --- /dev/null +++ b/meson.build @@ -0,0 +1,6 @@ +project('scrcpy', 'c', subproject_dir: '.') + +subproject('app') +subproject('server') + +run_target('run', command: ['scripts/run-scrcpy.sh']) diff --git a/scripts/run-scrcpy.sh b/scripts/run-scrcpy.sh new file mode 100755 index 00000000..62ff9b95 --- /dev/null +++ b/scripts/run-scrcpy.sh @@ -0,0 +1,2 @@ +#!/bin/bash +SCRCPY_SERVER_JAR="$MESON_BUILD_ROOT/server/scrcpy-server.jar" "$MESON_BUILD_ROOT/app/scrcpy" diff --git a/server/meson.build b/server/meson.build new file mode 100644 index 00000000..fa5dc727 --- /dev/null +++ b/server/meson.build @@ -0,0 +1,11 @@ +project('scrcpy-server', 'c') # not really c, but meson expects something + +# does not track dependencies, so meson does not guarantees that server is up to date +# call "touch server" or "ninja -t clean server/scrcpy-server.jar" before to rebuild +custom_target('scrcpy-server', + build_always: false, # do not enable, otherwise "sudo ninja install" will execute gradle! + input: '.', + output: 'scrcpy-server.jar', + command: [find_program('./scripts/build-wrapper.sh'), '@INPUT@', '@OUTPUT@', get_option('buildtype')], + install: true, + install_dir: 'share/scrcpy') diff --git a/server/scripts/build-wrapper.sh b/server/scripts/build-wrapper.sh new file mode 100755 index 00000000..c21e946f --- /dev/null +++ b/server/scripts/build-wrapper.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# Wrapper script to invoke gradle from meson +set -e + +PROJECT_ROOT="$1" +OUTPUT="$2" +BUILDTYPE="$3" + +# gradlew is in the parent of the server directory +GRADLE=${GRADLE:-$PROJECT_ROOT/../gradlew} + +if [[ "$BUILDTYPE" == debug ]] +then + "$GRADLE" -p "$PROJECT_ROOT" assembleDebug + cp "$PROJECT_ROOT/build/outputs/apk/debug/server-debug.apk" "$OUTPUT" +else + "$GRADLE" -p "$PROJECT_ROOT" assembleRelease + cp "$PROJECT_ROOT/build/outputs/apk/release/server-release-unsigned.apk" "$OUTPUT" +fi