Updated build system

This commit is contained in:
Frode Solheim 2021-03-15 18:08:55 +01:00
parent 264973530f
commit a4288eb84c
47 changed files with 1676 additions and 214 deletions

273
.github/workflows/fsbuild.yml vendored Normal file
View file

@ -0,0 +1,273 @@
name: Build
on:
push:
branches:
- master
- dev
- stable
pull_request:
branches:
- master
- dev
- stable
jobs:
Linux_x86-64:
runs-on: ubuntu-18.04
steps:
- name: Install deb packages
run: >-
sudo apt install
dos2unix
gettext
intltool
libao-dev
libasound2-dev
libevdev-dev
libgbm-dev
libgl-dev
libglu-dev
libopenal-dev
libpulse-dev
libudev-dev
libusb-1.0-0-dev
libx11-dev
libx11-xcb-dev
libxcb1-dev
libxcb-glx0-dev
libxcb-icccm4-dev
libxcb-image0-dev
libxcb-keysyms1-dev
libxcb-randr0-dev
libxcb-render-util0-dev
libxcb-shape0-dev
libxcb-shm0-dev
libxcb-sync0-dev
libxcb-xfixes0-dev
libxcb-xinerama0-dev
libxcursor-dev
libxext-dev
libxfixes-dev
libxi-dev
libxinerama-dev
libxrandr-dev
libxrender-dev
x11proto-dev
- name: Install pip packages
run: |
sudo python3 -m pip install -U pip setuptools
sudo python3 -m pip install -U meson ninja
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Cache dependencies
uses: actions/cache@v2
id: fsdeps_cache
with:
path: fsdeps/_prefix
key: fsdeps_${{ hashFiles('fsdeps/**/*') }}_${{ runner.os }}
- name: Build dependencies
if: steps.fsdeps_cache.outputs.cache-hit != 'true'
run: fsdeps/make
- name: Update version
run: fsbuild/version --update --auto
- name: Bootstrap
run: fsdeps/use fsbuild/bootstrap
- name: Configure
run: fsdeps/use fsbuild/configure
- name: Make
run: fsdeps/use fsbuild/make
- name: Bundle
run: fsdeps/use fsbuild/bundle
- name: Archive
run: fsbuild/archive
- uses: actions/upload-artifact@v2
with:
name: Linux_x86-64
path: fsbuild/_dist/*
- name: Upload build to Dropbox folder
if: >-
github.ref == 'refs/heads/master' ||
github.ref == 'refs/heads/dev' ||
github.ref == 'refs/heads/stable'
run: |
python3 -m pip install dropbox
fsbuild/upload
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
DROPBOX_ACCESS_TOKEN: ${{ secrets.DROPBOX_ACCESS_TOKEN }}
macOS_x86-64:
runs-on: macos-10.15
steps:
- name: Install brew packages
run: brew install autoconf automake dos2unix meson
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Cache dependencies
uses: actions/cache@v2
id: fsdeps_cache
with:
path: fsdeps/_prefix
key: fsdeps_${{ hashFiles('fsdeps/**/*') }}_${{ runner.os }}
- name: Build dependencies
if: steps.fsdeps_cache.outputs.cache-hit != 'true'
run: fsdeps/make
- name: Update version
run: fsbuild/version --update --auto
- name: Bootstrap
run: fsdeps/use fsbuild/bootstrap
- name: Configure
run: fsdeps/use fsbuild/configure
- name: Make
run: fsdeps/use fsbuild/make
- name: Bundle
run: fsbuild/bundle
- name: Prepare signing certificate
run: |
echo $SIGNING_CERTIFICATE_P12_DATA | base64 --decode > certificate.p12
security create-keychain -p $KEYCHAIN_PASSWORD build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p $KEYCHAIN_PASSWORD build.keychain
security import certificate.p12 -k build.keychain -P $SIGNING_CERTIFICATE_PASSWORD -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple: -s -k $KEYCHAIN_PASSWORD build.keychain
env:
KEYCHAIN_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
SIGNING_CERTIFICATE_P12_DATA: ${{ secrets.MACOS_CERTIFICATE_P12_DATA }}
SIGNING_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
- name: Sign
run: fsbuild/sign
- name: Notarize
run: fsbuild/notarize
env:
NOTARIZATION_PASSWORD: ${{ secrets.MACOS_NOTARIZATION_PASSWORD }}
NOTARIZATION_PROVIDER: ${{ secrets.MACOS_NOTARIZATION_PROVIDER }}
NOTARIZATION_USERNAME: ${{ secrets.MACOS_NOTARIZATION_USERNAME }}
- name: Archive
run: fsbuild/archive
- uses: actions/upload-artifact@v2
with:
name: macOS_x86-64
path: fsbuild/_dist/*
- name: Upload build to Dropbox folder
if: >-
github.ref == 'refs/heads/master' ||
github.ref == 'refs/heads/dev' ||
github.ref == 'refs/heads/stable'
run: |
python3 -m pip install dropbox
fsbuild/upload
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
DROPBOX_ACCESS_TOKEN: ${{ secrets.DROPBOX_ACCESS_TOKEN }}
Windows_x86-64:
runs-on: windows-2016
defaults:
run:
shell: msys2 {0}
steps:
- uses: msys2/setup-msys2@v2
with:
update: true
install: >-
autoconf
automake
base-devel
gettext
git
libtool
make
mingw-w64-x86_64-cmake
mingw-w64-x86_64-gcc
mingw-w64-x86_64-icoutils
mingw-w64-x86_64-meson
mingw-w64-x86_64-openal
mingw-w64-x86_64-pkg-config
mingw-w64-x86_64-python
mingw-w64-x86_64-python-pip
unzip
zip
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Cache dependencies
uses: actions/cache@v2
id: fsdeps_cache
with:
path: fsdeps/_prefix
key: fsdeps_${{ hashFiles('fsdeps/**/*') }}_${{ runner.os }}
- name: Build dependencies
if: steps.fsdeps_cache.outputs.cache-hit != 'true'
run: fsdeps/make
- name: Update version
run: fsbuild/version --update --auto
- name: Bootstrap
run: fsdeps/use fsbuild/bootstrap
- name: Configure
run: fsdeps/use fsbuild/configure
- name: Make
run: fsdeps/use fsbuild/make
- name: Bundle
run: fsbuild/bundle
- name: Archive
run: fsbuild/archive
- uses: actions/upload-artifact@v2
with:
name: Windows_x86-64
path: fsbuild/_dist/*
- name: Upload build to Dropbox folder
if: >-
github.ref == 'refs/heads/master' ||
github.ref == 'refs/heads/dev' ||
github.ref == 'refs/heads/stable'
run: |
python3 -m pip install dropbox
fsbuild/upload
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
DROPBOX_ACCESS_TOKEN: ${{ secrets.DROPBOX_ACCESS_TOKEN }}

4
.gitignore vendored
View file

@ -1,16 +1,16 @@
*~
autom4te.cache
/CAPSImg/configure
/CAPSImg/Makefile
config.h
config.h.in
config.log
config.status
configure
/dist.fs
*.dll
*.dll.a
*.dylib
*.log
Makefile
*.o
*.so
*.so.*

32
Makefile Normal file
View file

@ -0,0 +1,32 @@
uname := $(shell uname -a)
ifneq ($(findstring Msys,$(uname)),)
os := Windows
else
ifneq ($(findstring Darwin,$(uname)),)
os := macOS
else
os := Linux
endif
endif
all: build
build:
make -C CAPSImg
ifeq (${os},Windows)
cp CAPSImg/CAPSImg.dll capsimg.dll
else
ifeq (${os},macOS)
cp CAPSImg/libcapsimage.dylib capsimg.so
install_name_tool -id capsimg.so capsimg.so
else
cp CAPSImg/libcapsimage.so.5.1 capsimg.so
endif
endif
clean:
make -C CAPSImg clean
rm -Rf capsimg${dll} dist.fs
distclean: clean
make -C CAPSImg distclean

View file

@ -1,150 +0,0 @@
plugin = CAPSImg
executable =
# Makefile.fs begin common ---------------------------------------------------
version = $(shell cat VERSION.fs)
uname := $(shell uname -a)
ifneq ($(findstring Msys,$(uname)),)
os := Windows
arch := x86-64
exe := .exe
dll := .dll
opengl_libs := -lopengl32 -lglew32
else
ifneq ($(findstring Darwin,$(uname)),)
os := macOS
arch := x86-64
exe :=
dll := .so
opengl_libs := -framework OpenGL -lGLEW
else
os := Linux
arch := x86-64
exe :=
dll := .so
opengl_libs := -lGL -lGLEW
endif
endif
plugin_dir = dist.fs/${plugin}
data_dir = dist.fs/${plugin}/Data
licenses_dir = dist.fs/${plugin}/Licenses
locale_dir = dist.fs/${plugin}/Locale
os_arch_dir = dist.fs/${plugin}/${os}/${arch}
glib_cflags = $(shell pkg-config --cflags glib-2.0)
glib_libs = $(shell pkg-config --libs glib-2.0)
cppflags = -DFSGS -DFSEMU -DFSE ${glib_cflags}
libs = ${glib_libs} ${opengl_libs}
libs += -lpng -lSDL2_ttf -lsamplerate
fsemu-all: fsemu-build
@echo Built ${version} for ${os}_${arch}
.PHONY: assemble bootstrap build clean configure distclean install strip \
package plugin plugin-noclean rebuild
assemble: fsemu-assemble
bootstrap: fsemu-bootstrap
build: fsemu-build
clean: fsemu-clean
configure: fsemu-configure
distclean: fsemu-distclean
install: fsemu-install
strip: fsemu-strip
package: fsemu-package
plugin: fsemu-plugin
plugin-noclean: fsemu-plugin-noclean
rebuild: fsemu-rebuild
fsemu-rebuild: fsemu-bootstrap fsemu-configure fsemu-clean fsemu-build
fsemu-install: fsemu-plugin-noclean
rm -Rf ../../OpenRetro/System/${plugin}
mkdir -p ../../OpenRetro/System
mv dist.fs/${plugin} ../../OpenRetro/System
fsemu-assemble-pre:
rm -Rf ${plugin_dir}
mkdir -p ${plugin_dir}
echo "[plugin]" > ${plugin_dir}/Plugin.ini
echo "name = ${plugin}" >> ${plugin_dir}/Plugin.ini
echo "version = ${version}" >> ${plugin_dir}/Plugin.ini
fsemu-assemble-wrap: fsemu-assemble-pre fsemu-assemble
fsemu-plugin-noclean: fsemu-plugin-prep fsemu-build fsemu-assemble-wrap \
fsemu-strip fsemu-package
ifeq (${os},Linux)
if [ -d ${os_arch_dir} ]; then cp ${os_arch_dir}/*.so* .; fi
endif
fsemu-plugin-prep:
# Remove locally installed shared libraries (used for development)
# before building plugin, to avoid getting stale libraries included
# in the dist.
rm -f *.so*
fsemu-plugin: fsemu-bootstrap fsemu-configure fsemu-clean \
fsemu-plugin-noclean
# fsemu-plugin-clean:
# rm -Rf dist.fs/${plugin}
fsemu-package:
cd dist.fs && tar cfJ ${plugin}_${version}_${os}_${arch}.tar.xz ${plugin}
@echo Packaged ${version} for ${os}-${arch}
fsemu-strip:
./standalone.fs ${os_arch_dir}
ifeq (${os},macOS)
ifneq (${executable},)
./wrap-macos.fs ${os_arch_dir} ${plugin} ${executable}
endif
endif
# Makefile.fs end common -----------------------------------------------------
fsemu-bootstrap:
./bootstrap.fs
fsemu-configure:
ifeq (${os},Windows)
./configure.fs --enable-static
else
./configure.fs
endif
fsemu-build:
make -C CAPSImg
ifeq (${os},Windows)
cp CAPSImg/CAPSImg.dll capsimg.dll
else
ifeq (${os},macOS)
cp CAPSImg/libcapsimage.dylib capsimg.so
install_name_tool -id capsimg.so capsimg.so
else
cp CAPSImg/libcapsimage.so.5.1 capsimg.so
endif
endif
fsemu-clean:
make -C CAPSImg clean
rm -Rf capsimg${dll} dist.fs
fsemu-distclean: clean
make -C CAPSImg distclean
fsemu-assemble:
mkdir -p ${plugin_dir}
echo ${version} > ${plugin_dir}/Version.txt
cp README.fs ${plugin_dir}/ReadMe.txt
mkdir -p ${os_arch_dir}
echo ${version} > ${os_arch_dir}/Version.txt
cp capsimg${dll} ${os_arch_dir}
mkdir -p ${licenses_dir}
cp LICENCE.txt ${licenses_dir}/CAPSImg.txt

10
PACKAGE.FS Normal file
View file

@ -0,0 +1,10 @@
PACKAGE_COMMIT=
PACKAGE_MACOS_BUNDLE_ID=dev.solheim.capsimg
PACKAGE_NAME=capsimg
PACKAGE_NAME_PRETTY=CAPSImg
PACKAGE_TYPE=fs-library-plugin
PACKAGE_VERSION=5.1.0.4-fs
PACKAGE_VERSION_MAJOR=5
PACKAGE_VERSION_MINOR=1
PACKAGE_VERSION_REVISION=0
PACKAGE_VERSION_TAG=-fs

View file

@ -1 +0,0 @@
5.1fs3

View file

@ -1,4 +1,7 @@
#!/bin/sh -e
#!/bin/sh
set -e
echo "Boostrapping capsimg..."
cd CAPSImg
rm -Rf autom4te.cache
@ -7,6 +10,4 @@ autoheader
echo "Running autoconf"
autoconf
cd ..
echo "Bootstrap done, you can now run ./configure.fs"
echo "Bootstrap done, you can now run ./configure"

View file

@ -1,8 +1,10 @@
#!/bin/sh -e
#!/bin/sh
set -e
cd CAPSImg
if [ "$1" = "--enable-static" ]; then
LDFLAGS="-static -static-libgcc -static-libstdc++" ./configure
else
./configure "$@"
fi
cd ..

4
fsbuild/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
# fsbuild/.gitignore
# This file is automatically generated by fs-package
/_*

12
fsbuild/all Executable file
View file

@ -0,0 +1,12 @@
#!/bin/sh
# This file is automatically generated by fs-package
set -e
fsbuild/bootstrap
fsbuild/configure
fsbuild/make
fsbuild/bundle
fsbuild/sign
fsbuild/notarize
fsbuild/archive

23
fsbuild/archive Executable file
View file

@ -0,0 +1,23 @@
#!/bin/sh
# This file is automatically generated by fs-package
set -e
. ./PACKAGE.FS
. fsbuild/system.sh
mkdir -p fsbuild/_dist
cd fsbuild/_build
if [ "$SYSTEM_OS" = "Windows" ]; then
ARCHIVE=${PACKAGE_NAME_PRETTY}_${PACKAGE_VERSION}_${SYSTEM_OS}_${SYSTEM_ARCH}.zip
zip -r ../_dist/$ARCHIVE ${PACKAGE_NAME_PRETTY}
else
ARCHIVE=${PACKAGE_NAME_PRETTY}_${PACKAGE_VERSION}_${SYSTEM_OS}_${SYSTEM_ARCH}.tar.xz
tar cfJv ../_dist/$ARCHIVE ${PACKAGE_NAME_PRETTY}
fi
echo -------------------------------------------------------------------------\
-------
echo "[FSBUILD] Archived fsbuild/_dist/$ARCHIVE"

12
fsbuild/bootstrap Executable file
View file

@ -0,0 +1,12 @@
#!/bin/sh
# This file is automatically generated by fs-package
set -e
if [ -f fsbuild/bootstrap.sh ]; then
. fsbuild/bootstrap.sh
elif [ -f fsplugin/Makefile ]; then
make -C fsplugin bootstrap
elif [ -f ./bootstrap ]; then
./bootstrap
fi

12
fsbuild/build Executable file
View file

@ -0,0 +1,12 @@
#!/bin/sh
# This file is automatically generated by fs-package
set -e
if [ -f fsbuild/build.sh ]; then
. fsbuild/build.sh
elif [ -f fsplugin/Makefile ]; then
make -C fsplugin "$@"
elif [ -f ./Makefile ]; then
make "$@"
fi

29
fsbuild/bundle Executable file
View file

@ -0,0 +1,29 @@
#!/bin/sh
# This file is automatically generated by fs-package
set -e
. ./PACKAGE.FS
if [ -f fsbuild/bundle.sh ]; then
. fsbuild/bundle.sh
elif [ -f bundle.sh ]; then
. ./bundle.sh
elif [ -f fsplugin/Makefile ]; then
# make -C fsplugin fsemu-plugin-prep
# make -C fsplugin fsemu-build
make -C fsplugin fsemu-assemble-wrap
make -C fsplugin fsemu-strip
# make -C fsplugin plugin-noclean
mkdir -p fsbuild/_build
rm -Rf fsbuild/_build/$PACKAGE_NAME_PRETTY
mv fsplugin/build/$PACKAGE_NAME_PRETTY fsbuild/_build/$PACKAGE_NAME_PRETTY
fi
echo -------------------------------------------------------------------------\
-------
echo "[FSBUILD] fsbuild/_build/$PACKAGE_NAME_PRETTY"

20
fsbuild/bundle.sh Normal file
View file

@ -0,0 +1,20 @@
#!/bin/sh
set -e
. fsbuild/plugin.pre.sh
mkdir -p $PLUGIN_BINDIR
cp capsimg$SYSTEM_DLL $PLUGIN_BINDIR
mkdir -p $PLUGIN_READMEDIR
cp README.md $PLUGIN_READMEDIR/ReadMe.txt
mkdir -p $PLUGIN_LICENSESDIR
cp LICENCE.txt $PLUGIN_LICENSESDIR/CAPSImg.txt
if [ $SYSTEM_OS = "macOS" ]; then
cp $PLUGIN_BINDIR/capsimg.so $PLUGIN_BINDIR/capsimg.dylib
fi
. fsbuild/plugin.post.sh

14
fsbuild/clean Executable file
View file

@ -0,0 +1,14 @@
#!/bin/sh
# This file is automatically generated by fs-package
set -e
rm -Rf fsbuild/_*
if [ -f fsbuild/clean.sh ]; then
. fsbuild/clean.sh
elif [ -f fsplugin/Makefile ]; then
make -C fsplugin clean
elif [ -f ./Makefile ]; then
make clean
fi

6
fsbuild/clean.sh Normal file
View file

@ -0,0 +1,6 @@
# /bin/sh
set -e
echo "Disabling clean because make clean deletes libraries from fsdeps"
exit 1

12
fsbuild/configure vendored Executable file
View file

@ -0,0 +1,12 @@
#!/bin/sh
# This file is automatically generated by fs-package
set -e
if [ -f fsbuild/configure.sh ]; then
. fsbuild/configure.sh
elif [ -f fsplugin/Makefile ]; then
make -C fsplugin configure
elif [ -f ./configure ]; then
./configure
fi

11
fsbuild/configure.sh Normal file
View file

@ -0,0 +1,11 @@
#!/bin/sh
set -e
. fsbuild/system.sh
if [ $SYSTEM_OS = "Windows" ]; then
./configure --enable-static
else
./configure
fi

47
fsbuild/download.py Normal file
View file

@ -0,0 +1,47 @@
#!/usr/bin/env python3
# This file is automatically generated by fs-package
import hashlib
import os
import sys
url = sys.argv[1]
checksum = sys.argv[2]
if checksum.startswith("sha256:"):
h = hashlib.sha256
checksum = checksum[7:]
else:
raise Exception("Unknown hash function")
def verify():
with open(archive, "rb") as f:
actual_checksum = h(f.read()).hexdigest()
result = actual_checksum == checksum
if result:
print("Checksum verified")
else:
print("Checksum verification failed")
print("Expected", checksum)
print("But got:", actual_checksum)
return result
archive = url.split("/")[-1]
if not os.path.exists("fsbuild/_sources"):
os.makedirs("fsbuild/_sources")
archive = os.path.join("fsbuild/_sources", archive)
if os.path.exists(archive):
if verify():
sys.exit(0)
print("Removing archive", archive)
os.remove(archive)
# FIXME: Replace use of wget, just use python instead
if os.system(f"cd fsbuild/_sources && wget \"{url}\"") != 0:
print("Failed to download")
sys.exit(1)
if not verify():
sys.exit(2)

48
fsbuild/frameworkify.sh Normal file
View file

@ -0,0 +1,48 @@
#!/bin/sh
# This file is automatically generated by fs-package
set -e
DIR=$1
BUNDLE_NAME=$2
EXECUTABLE=$3
BUNDLE_ID=$4
TEMP_BUNDLE=fsbuild/_build/temp.app
echo "Creating temporary framework at $TEMP_BUNDLE"
rm -Rf $TEMP_BUNDLE
mkdir -p $TEMP_BUNDLE
echo "Move $DIR/$EXECUTABLE.dylib -> $TEMP_BUNDLE/$BUNDLE_NAME"
mv $DIR/$EXECUTABLE.dylib $TEMP_BUNDLE/$BUNDLE_NAME
echo "Writing Info.plist"
mkdir -p $TEMP_BUNDLE/Resources
P=$TEMP_BUNDLE/Resources/Info.plist
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" >> $P
echo "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">" >> $P
echo "<plist version=\"1.0\">" >> $P
echo "<dict>" >> $P
echo "<key>CFBundleDevelopmentRegion</key>" >> $P
echo "<string>English</string>" >> $P
echo "<key>CFBundleExecutable</key>" >> $P
echo "<string>$BUNDLE_NAME</string>" >> $P
echo "<key>CFBundleIdentifier</key>" >> $P
echo "<string>$BUNDLE_ID</string>" >> $P
echo "<key>CFBundleInfoDictionaryVersion</key>" >> $P
echo "<string>6.0</string>" >> $P
echo "<key>CFBundleName</key>" >> $P
echo "<string>$BUNDLE_NAME</string>" >> $P
echo "<key>CFBundlePackageType</key>" >> $P
echo "<string>FMWK</string>" >> $P
echo "<key>CFBundleShortVersionString</key>" >> $P
echo "<string>1.0.0</string>" >> $P
echo "<key>CFBundleSignature</key>" >> $P
echo "<string>????</string>" >> $P
echo "<key>CFBundleVersion</key>" >> $P
echo "<string>1.0.0</string>" >> $P
echo "</dict>" >> $P
echo "</plist>" >> $P
echo "Moving $TEMP_BUNDLE -> $DIR/$BUNDLE_NAME.framework"
mv $TEMP_BUNDLE $DIR/$BUNDLE_NAME.framework

6
fsbuild/make Executable file
View file

@ -0,0 +1,6 @@
#!/bin/sh
# This file is automatically generated by fs-package
set -e
fsbuild/build

106
fsbuild/notarize Executable file
View file

@ -0,0 +1,106 @@
#!/usr/bin/env python3
# This file is automatically generated by fs-package
import os
import subprocess
import sys
import time
import xml.etree.ElementTree as ET
package = {}
with open("PACKAGE.FS", "r") as f:
for line in f:
try:
key, value = line.strip().split("=", 1)
package[key] = value
except ValueError:
pass
if package["PACKAGE_TYPE"] == "fs-data-plugin":
print("Not signing data plugin")
sys.exit(0)
package_name_pretty = package["PACKAGE_NAME_PRETTY"]
bundle_id = package["PACKAGE_MACOS_BUNDLE_ID"]
app = package_name_pretty + ".app"
framework = package_name_pretty + ".framework"
arch = "x86-64" # FIXME
apple_id_user = os.environ.get("NOTARIZATION_USERNAME", "")
itc_provider = os.environ.get("NOTARIZATION_PROVIDER", "")
def macos_bundle_path():
path = f"fsbuild/_build/{package_name_pretty}/macOS/{arch}/{app}"
if os.path.exists(path):
return path
path = f"fsbuild/_build/{package_name_pretty}/macOS/{arch}/{framework}"
if os.path.exists(path):
return path
raise Exception("Could not find any app or framework bundle")
def shell(cmd):
print(cmd)
return subprocess.run(
cmd, shell=True, check=True, stdout=subprocess.PIPE).stdout.decode("UTF-8")
def main():
if sys.platform != "darwin":
print("Skipping notarize step (Not a macOS build)")
return
bundle_path = macos_bundle_path()
bundle = os.path.basename(bundle_path)
bundle_parent_dir = os.path.dirname(bundle_path)
shell("rm -f fsbuild/_build/notarize.zip")
zip = "../../../notarize.zip"
shell(f'cd {bundle_parent_dir} && ditto -c -k --keepParent "{bundle}" "{zip}"')
result = shell(
"xcrun altool --notarize-app -t osx "
"-f fsbuild/_build/notarize.zip "
"--primary-bundle-id {bundle_id} "
"-u {apple_id_user} "
"-p @env:NOTARIZATION_PASSWORD "
"-itc_provider {itc_provider} "
"--output-format xml".format(
bundle_id=bundle_id,
apple_id_user=apple_id_user,
itc_provider=itc_provider,
)
)
print(result)
root = ET.fromstring(result)
dict = root.find("dict")
print(dict)
request_uuid = dict.find("dict").find("string").text
print(request_uuid)
for i in range(60):
time.sleep(10.0)
result = shell(
"xcrun altool --notarization-info {} "
"-u {} -p @env:NOTARIZATION_PASSWORD "
"-itc_provider {} --output-format xml".format(
request_uuid, apple_id_user, itc_provider
)
)
if "<string>success</string>" in result:
break
elif "<string>in progress</string>" in result:
print("in progress...")
continue
else:
print(result)
raise Exception("...")
if bundle_path.endswith(".framework"):
print("Does not seem to be possible to staple tickets to frameworks? (error 73)")
print("Exiting...")
sys.exit(0)
print('xcrun stapler staple "{}"'.format(bundle_path))
assert os.system('xcrun stapler staple "{}"'.format(bundle_path)) == 0
if __name__ == "__main__":
main()

48
fsbuild/plugin.post.sh Normal file
View file

@ -0,0 +1,48 @@
# Intended for sourcing by other shell scripts
# This file is automatically generated by fs-package
. ./fsbuild/system.sh
. ./PACKAGE.FS
if [ "$SYSTEM_OS" = "macOS" ]; then
if [ "$PLUGIN_APPIFY" = "0" ]; then
echo "Skip appify"
elif [ "$PLUGIN_SKIP_APPIFY" = "1" ]; then
echo "Skip appify"
elif [ -d "$PLUGIN_BINDIR/$PACKAGE_NAME_PRETTY.app" ]; then
echo "App bundle already exists"
else
if [ "$EXECUTABLE" = "" ]; then
EXECUTABLE=$PACKAGE_NAME
fi
if [ $PACKAGE_TYPE = "fsemu-plugin/dll" ]; then
sh fsbuild/frameworkify.sh $PLUGIN_BINDIR $PACKAGE_NAME_PRETTY \
$EXECUTABLE $PACKAGE_MACOS_BUNDLE_ID
else
sh fsbuild/appify.sh $PLUGIN_BINDIR $PACKAGE_NAME_PRETTY \
$EXECUTABLE $PACKAGE_MACOS_BUNDLE_ID
fi
fi
fi
if [ "$PLUGIN_STANDALONE" = "0" ]; then
echo "Skip standalone"
elif [ "$PLUGIN_SKIP_STANDALONE" = "1" ]; then
echo "Skip standalone"
else
# python3 fsbuild/standalone.py $PLUGIN_BINDIR
LIBGPG_ERROR_CHECK=0 python3 fsbuild/standalone.py $PLUGIN_BINDIR
fi
echo "[plugin]" > $PLUGIN_DIR/Plugin.ini
echo "name = $PACKAGE_NAME_PRETTY" >> $PLUGIN_DIR/Plugin.ini
echo "version = $PACKAGE_VERSION" >> $PLUGIN_DIR/Plugin.ini
unix2dos $PLUGIN_DIR/Plugin.ini
echo "$PACKAGE_VERSION" > $PLUGIN_DIR/Version.txt
unix2dos $PLUGIN_DIR/Version.txt
if [ -d $PLUGIN_BINDIR ]; then
echo "$PACKAGE_VERSION" > $PLUGIN_BINDIR/Version.txt
unix2dos $PLUGIN_BINDIR/Version.txt
fi

33
fsbuild/plugin.pre.sh Normal file
View file

@ -0,0 +1,33 @@
# Intended for sourcing by other shell scripts
# This file is automatically generated by fs-package
. ./fsbuild/system.sh
. ./PACKAGE.FS
PLUGIN_VERSION=$PACKAGE_VERSION
PLUGIN_DIR=fsbuild/_build/$PACKAGE_NAME_PRETTY
PLUGIN_BINDIR=$PLUGIN_DIR/$SYSTEM_OS/$SYSTEM_ARCH
PLUGIN_DOCSDIR=$PLUGIN_DIR/Docs
PLUGIN_READMEDIR=$PLUGIN_DIR
PLUGIN_LICENSESDIR=$PLUGIN_DIR/Licenses
# For now
PLUGIN_DATADIR=$PLUGIN_BINDIR
PLUGIN_REALDATADIR=$PLUGIN_DIR/Data
# FIXME: Deprecate $EXE (Use $SYSTEM_EXE instead)
if [ "$SYSTEM_OS" = "Windows" ]; then
EXE=.exe
else
EXE=
fi
if [ "$SYSTEM_OS" = "macOS" ]; then
PLUGIN_APPDIR=$PLUGIN_BINDIR/$PACKAGE_NAME.app
# PLUGIN_MACOSDIR=$PLUGIN_BINDIR/$PACKAGE_NAME.app/Contents/MacOS
# PLUGIN_RESOURCESDIR=$PLUGIN_BINDIR/$PACKAGE_NAME.app/Contents/Resources
# For now
PLUGIN_DATADIR=$PLUGIN_APPDIR/Contents/Resources/Data
fi
rm -Rf $PLUGIN_DIR

9
fsbuild/rebuild Executable file
View file

@ -0,0 +1,9 @@
#!/bin/sh
# This file is automatically generated by fs-package
set -e
fsbuild/clean
fsbuild/bootstrap
fsbuild/configure
fsbuild/make "$@"

89
fsbuild/sign Executable file
View file

@ -0,0 +1,89 @@
#!/usr/bin/env python3
# This file is automatically generated by fs-package
import os
import sys
import time
import subprocess
package = {}
with open("PACKAGE.FS", "r") as f:
for line in f:
try:
key, value = line.strip().split("=", 1)
package[key] = value
except ValueError:
pass
if package["PACKAGE_TYPE"] == "fs-data-plugin":
print("Not signing data plugin")
sys.exit(0)
package_name_pretty = package["PACKAGE_NAME_PRETTY"]
app = package_name_pretty + ".app"
framework = package_name_pretty + ".framework"
arch = "x86-64" # FIXME
# def get_package():
# global _package_name
# if _package_name is None:
# with open("fsbuild/PACKAGE", "r") as f:
# _package_name = f.read().strip()
# return _package_name
# def get_arch():
# # FIXME: Detect properly
# return "x86-64"
def macos_bundle_path():
path = f"fsbuild/_build/{package_name_pretty}/macOS/{arch}/{app}"
if os.path.exists(path):
return path
path = f"fsbuild/_build/{package_name_pretty}/macOS/{arch}/{framework}"
if os.path.exists(path):
return path
raise Exception("Could not find any app or framework bundle")
def q(arg):
if " " in arg:
return f'"{arg}"'
return arg
def macos_sign():
# Signing sometimes fails due to Apple errors (timeouts, etc). So we try
# multiple times before giving up.
for i in range(20):
args = [
"codesign",
"-f",
"--deep",
"--options=runtime",
"-s",
"Developer ID Application",
]
if os.path.exists("fsbuild/Entitlements.plist"):
args.extend(["--entitlements", "fsbuild/Entitlements.plist"])
args.append(macos_bundle_path())
print(" ".join(f"{q(a)}" for a in args))
p = subprocess.Popen(args)
if p.wait() == 0:
break
time.sleep(1.0 * i)
print("Attempt", i + 2)
else:
print("Giving up")
sys.exit(1)
def main():
if sys.platform == "darwin":
macos_sign()
else:
print("Skipping sign step (No signatures for this platform")
if __name__ == "__main__":
main()

229
standalone.fs → fsbuild/standalone.py Executable file → Normal file
View file

@ -1,4 +1,6 @@
#!/usr/bin/env python3
# This file is automatically generated by fs-package
import os
import sys
import shutil
@ -12,6 +14,10 @@ no_copy = False
steam_runtime = False
excluded_libraries = {}
included_libraries = {}
def fix_linux_binary(path):
changes = 0
if os.path.exists(path + ".standalone"):
@ -21,11 +27,19 @@ def fix_linux_binary(path):
# find library locations
args = ["ldd", path]
p = subprocess.Popen(args, stdout=subprocess.PIPE)
print(args)
# p = subprocess.Popen(args, stdout=subprocess.PIPE)
# if p.wait() != 0:
# return 0
p = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# noinspection PyUnresolvedReferences
data = p.stdout.read().decode("UTF-8")
if p.wait() != 0:
if p.returncode != 0:
if p.stderr == b"\tnot a dynamic executable\n":
pass
else:
print(repr(p.stderr))
return 0
data = p.stdout.decode("UTF-8")
print("fixing", path, "no_copy =", no_copy)
library_locations = {}
for line in data.split("\n"):
@ -50,21 +64,27 @@ def fix_linux_binary(path):
library = line.split(" ")[-1]
print(library)
if ignore_linux_library(library):
excluded_libraries.setdefault(library, set()).add(path)
continue
library_source = library_locations[library]
library_source = os.path.normpath(library_source)
print(library, library_source)
# if steam_runtime and library_source.startswith(steam_runtime):
# if steam_runtime and not library_source.startswith("/usr/local"):
if steam_runtime and not library_source.startswith("/home"):
print("skipping steam runtime library")
continue
# if steam_runtime and not library_source.startswith("/home"):
# print("skipping steam runtime library")
# excluded_libraries.setdefault(library_source, set()).add(path)
# continue
if no_copy:
print("no_copy is set")
continue
# included_libraries.setdefault(library_source, set()).add(path)
dst = os.path.join(os.path.dirname(path), library)
if not os.path.exists(dst):
print("copying", library)
# For now, only add the dependent causing this to be copied
included_libraries.setdefault(library_source, set()).add(path)
print("[FSBUILD] Copy", library_source)
print("Needed by:", path)
shutil.copy(library_source, dst)
os.chmod(dst, 0o644)
changes += 1
@ -82,6 +102,32 @@ def fix_linux_binary(path):
return changes
# FIXME: Print warning if excluded libraries is not in this list?
manylinux2014_whitelist = set(
[
"libgcc_s.so.1",
"libstdc++.so.6",
"libm.so.6",
"libdl.so.2",
"librt.so.1",
"libc.so.6",
"libnsl.so.1",
"libutil.so.1",
"libpthread.so.0",
"libresolv.so.2",
"libX11.so.6",
"libXext.so.6",
"libXrender.so.1",
"libICE.so.6",
"libSM.so.6",
"libGL.so.1",
"libgobject-2.0.so.0",
"libgthread-2.0.so.0",
"libglib-2.0.so.0",
]
)
def ignore_linux_library(name):
if os.getenv("LIBGPG_ERROR_CHECK", "") != "0":
if name.startswith("libgpg-error.so"):
@ -89,6 +135,7 @@ def ignore_linux_library(name):
"Bundling libgpg-error (libgcrypt?) breaks Intel GL driver"
)
# Skip the dynamic linker for all known architectures
if name.startswith("linux-gate.so"):
return True
if name.startswith("linux-vdso.so"):
@ -97,16 +144,14 @@ def ignore_linux_library(name):
return True
if name.startswith("ld-linux-x86-64.so"):
return True
if name.startswith("ld-linux-armhf.so.3"):
return True
# Bundling the C library is a no-no (causes issues)
if name.startswith("libc.so"):
return True
if name.startswith("libstdc++.so"):
# Including libstdc++.sp breaks libGL loading with Intel on Ubuntu 16.10
# libGL error: unable to load driver: i965_dri.so
return True
if name.startswith("libgcc_s.so"):
# Might as well skip this one also, to avoid potential similar problems.
return True
# These are also system and/or libc libraries that we want to skip
if name.startswith("libpthread.so"):
return True
if name.startswith("libm.so"):
@ -119,10 +164,22 @@ def ignore_linux_library(name):
return True
if name.startswith("libutil.so"):
return True
# Including libstdc++.sp breaks libGL loading with Intel on Ubuntu 16.10
# libGL error: unable to load driver: i965_dri.so
if name.startswith("libstdc++.so"):
return True
# Might as well skip this one also, to avoid potential problems. This
# probably requires that we compile with a not-too-recent GCC version.
if name.startswith("libgcc_s.so"):
return True
# Problem with OpenAL on Ubuntu 16.04 if this is included
# if name.startswith("libpcre.so"):
# # Problem with OpenAL on Ubuntu 16.04 if this is included.
# return True
# OpenGL libraries should definitively not be distributed
if name.startswith("libGL.so"):
return True
if name.startswith("libGLU.so"):
@ -130,11 +187,12 @@ def ignore_linux_library(name):
if name.startswith("libEGL.so"):
return True
# Alsa library is in LSB, looks like only "old" interfaces likely to exist
# on all system are used by SDL2.
if name.startswith("libasound.so"):
# Alsa library is in LSB, looks like only "old" interfaces are used
# by SDL2.
return True
# X libraries are assumed to exist on the host system
if name.startswith("libX11.so"):
return True
if name.startswith("libXext.so"):
@ -151,6 +209,7 @@ def ignore_linux_library(name):
return True
if name.startswith("libXxf86vm.so"):
return True
# FIXME: Why was this commented out?
# if name.startswith("libxkbcommon.so"):
# return True
if name.startswith("libxcb.so"):
@ -162,7 +221,7 @@ def ignore_linux_library(name):
def linux_iteration(app):
binaries = []
binaries_dir = app
for name in os.listdir(binaries_dir):
for name in sorted(os.listdir(binaries_dir)):
binaries.append(os.path.join(binaries_dir, name))
changes = 0
for binary in binaries:
@ -187,7 +246,7 @@ def linux_main():
changes = linux_iteration(app)
if changes == 0:
break
for name in os.listdir(app):
for name in sorted(os.listdir(app)):
if name.endswith(".standalone"):
os.remove(os.path.join(app, name))
@ -230,7 +289,8 @@ def fix_macos_binary(path, frameworks_dir):
else:
dst = os.path.join(frameworks_dir, os.path.basename(old))
if not os.path.exists(dst):
print("copying", old)
print("[FSBUILD] Copy", old)
print("Needed by:", path)
shutil.copy(old, dst)
os.chmod(dst, 0o644)
changes += 1
@ -257,11 +317,11 @@ def macos_iteration(app):
# mac_os_dir = os.path.join(app, "Contents", "MacOS")
frameworks_dir = app
# frameworks_dir = os.path.join(app, "Contents", "Frameworks")
# for name in os.listdir(mac_os_dir):
# for name in sorted(os.listdir(mac_os_dir)):
# binaries.append(os.path.join(mac_os_dir, name))
# for name in os.listdir(frameworks_dir):
# binaries.append(os.path.join(frameworks_dir, name))
for name in os.listdir(app):
for name in sorted(os.listdir(app)):
binaries.append(os.path.join(app, name))
else:
binaries.append(app)
@ -271,6 +331,65 @@ def macos_iteration(app):
return changes
def fix_macos_binary_2(path, frameworks_dir):
print("fixing", path)
changes = 0
if not os.path.exists(path):
raise Exception("could not find " + repr(path))
args = ["otool", "-L", path]
p = subprocess.Popen(args, stdout=subprocess.PIPE)
# noinspection PyUnresolvedReferences
data = p.stdout.read().decode("UTF-8")
p.wait()
for line in data.split("\n"):
line = line.strip()
if not line:
continue
if line.startswith("/usr/lib") or line.startswith("/System"):
# old = line.split(" ")[0]
continue
if line.startswith("@executable_path"):
continue
old = line.split(" ")[0]
if "Contents" in old:
continue
print(old)
old_dir, name = os.path.split(old)
new = old.replace(old, "@executable_path/../Frameworks/" + name)
dst = os.path.join(frameworks_dir, os.path.basename(old))
if not os.path.exists(dst):
print("[FSBUILD] Copy", old)
print("Needed by:", path)
shutil.copy(old, dst)
os.chmod(dst, 0o644)
changes += 1
if os.path.basename(path) == os.path.basename(old):
args = ["install_name_tool", "-id", new, path]
else:
args = ["install_name_tool", "-change", old, new, path]
print(args)
p = subprocess.Popen(args)
assert p.wait() == 0
return changes
def macos_iteration_2(app):
binaries = []
mac_os_dir = os.path.join(app, "Contents", "MacOS")
frameworks_dir = os.path.join(app, "Contents", "Frameworks")
if not os.path.exists(frameworks_dir):
os.makedirs(frameworks_dir)
for name in os.listdir(mac_os_dir):
binaries.append(os.path.join(mac_os_dir, name))
# if os.path.exists(frameworks_dir):
for name in os.listdir(frameworks_dir):
binaries.append(os.path.join(frameworks_dir, name))
changes = 0
for binary in binaries:
changes += fix_macos_binary_2(binary, frameworks_dir)
return changes
def macos_main():
global rpath, no_copy
if "--rpath" in sys.argv:
@ -279,17 +398,24 @@ def macos_main():
if "--no-copy" in sys.argv:
sys.argv.remove("--no-copy")
no_copy = True
app = sys.argv[1]
while True:
changes = macos_iteration(app)
if changes == 0:
break
app_dir = sys.argv[1]
for item in os.listdir(app_dir):
if not item.endswith(".app"):
continue
app = os.path.join(app_dir, item)
while True:
changes = macos_iteration_2(app)
if changes == 0:
break
windows_system_dlls = [
"advapi32.dll",
"dinput.dll",
"dsound.dll",
"dwmapi.dll",
"gdi32.dll",
"iphlpapi.dll",
"imm32.dll",
"kernel32.dll",
"msvcrt.dll",
@ -304,6 +430,7 @@ windows_system_dlls = [
"user32.dll",
"userenv.dll",
"usp10.dll",
"uxtheme.dll",
"version.dll",
"winmm.dll",
"ws2_32.dll",
@ -312,9 +439,13 @@ windows_system_dlls = [
def fix_windows_binary(path, app_dir):
if path.endswith(".txt"):
name, ext = os.path.splitext(os.path.basename(path))
if ext.lower() not in [".dll", ".exe"]:
return 0
# if path.endswith(".txt"):
# return 0
print("fixing", path)
fix_dll_name = os.path.basename(path).lower()
changes = 0
if not os.path.exists(path):
raise Exception("could not find " + repr(path))
@ -332,19 +463,33 @@ def fix_windows_binary(path, app_dir):
continue
if line.endswith("Summary"):
break
if not line.endswith(".dll"):
if line.startswith("Dump of file"):
continue
if line.startswith("File Type:"):
continue
if not line.lower().endswith(".dll"):
continue
src = line
if src.lower() in windows_system_dlls:
excluded_libraries.setdefault(src.lower(), set()).add(fix_dll_name)
continue
print(src)
src = os.environ["MINGW_PREFIX"] + "/bin/" + src
print(src)
dll_name = src
print(dll_name)
if True:
src = os.path.join("fsdeps", "_prefix", "bin", dll_name)
print("Checking", src)
if not os.path.exists(src):
src = os.environ["MINGW_PREFIX"] + "/bin/" + dll_name
print("Checking", src)
print(src)
included_libraries.setdefault(src, set()).add(
fix_dll_name
)
dst = os.path.join(app_dir, os.path.basename(src))
if not os.path.exists(dst):
print("copying", src)
print("[FSBUILD] Copy", src)
print("Needed by:", path)
shutil.copy(src, dst)
os.chmod(dst, 0o644)
changes += 1
@ -362,7 +507,7 @@ def fix_windows_binary(path, app_dir):
def windows_iteration(app):
binaries = []
if os.path.isdir(app):
for name in os.listdir(app):
for name in sorted(os.listdir(app)):
binaries.append(os.path.join(app, name))
# else:
# binaries.append(app)
@ -391,3 +536,19 @@ if __name__ == "__main__":
strip = True
sys.argv.extend(["--rpath=$ORIGIN"])
linux_main()
if excluded_libraries:
print("")
for library in sorted(excluded_libraries.keys()):
print("[FSBUILD] Exclude", library)
for dependent in sorted(excluded_libraries[library]):
print(" - depended on by", os.path.basename(dependent))
# print("Included libraries:")
if included_libraries:
print("")
for library in sorted(included_libraries.keys()):
print("[FSBUILD] Include", os.path.basename(library))
print(" - from", os.path.dirname(library))
for dependent in sorted(included_libraries[library]):
print(" - depended on by", os.path.basename(dependent))
print("")

23
fsbuild/system.sh Normal file
View file

@ -0,0 +1,23 @@
# Intended for sourcing by other shell scripts
# This file is automatically generated by fs-package
case "`uname`" in
Linux*) SYSTEM_OS=Linux;;
Darwin*) SYSTEM_OS=macOS;;
MINGW*) SYSTEM_OS=Windows;;
*) SYSTEM_OS=Unknown;;
esac
# FIXME: Remove hardcoded value
SYSTEM_ARCH=x86-64
if [ $SYSTEM_OS = "Windows" ]; then
SYSTEM_EXE=.exe
SYSTEM_DLL=.dll
else
SYSTEM_EXE=
SYSTEM_DLL=.so
fi
# FIXME: Deprecated alias
SYSTEM=$SYSTEM_OS

82
fsbuild/upload Executable file
View file

@ -0,0 +1,82 @@
#!/usr/bin/env python3
# This file is automatically generated by fs-package
import os
import dropbox
import requests
package_data = {}
with open("PACKAGE.FS", "r") as f:
for line in f:
try:
key, value = line.strip().split("=", 1)
package_data[key] = value
except ValueError:
pass
def execute_discord_webhook(name, link):
webhook_url = os.getenv("DISCORD_WEBHOOK_URL")
if not webhook_url:
return
content = (
f"`{name}` was built and uploaded to a Dropbox "
f"[shared folder]({link})"
)
requests.post(webhook_url, {"content": content, "username": "Builder"})
def upload_branch_name():
ref = os.getenv("GITHUB_REF", "")
if ref == "refs/heads/master":
return "Master"
elif ref == "refs/heads/dev":
return "Dev"
elif ref == "refs/heads/stable":
return "Stable"
return None
def upload(dbx, package, version, path):
print("Upload", path)
name = os.path.basename(path)
assert package in name
assert version in name
branch = upload_branch_name()
if not branch:
print("No upload branch name, skipping upload")
return
dst = f"/Builds/CI/{package}/{branch}/{version}/{name}"
with open(path, "rb") as f:
dbx.files_upload(f.read(), dst)
print("Uploaded ->", dst)
if os.getenv("DISCORD_WEBHOOK_URL"):
result = dbx.sharing_list_shared_links(f"/Builds/CI/{package}")
for link in result.links:
if link.path_lower == f"/Builds/CI/{package}".lower():
url = link.url
print("Found Dropbox shared link:", url)
break
else:
# Fallback URL, use first result returned
url = result.links[0].url
print("Found Dropbox shared (fallback) link:", url)
execute_discord_webhook(name, url)
def main():
dist_dir = "fsbuild/_dist"
upload_items = os.listdir(dist_dir)
# Require there to be exactly one dist file for now
assert len(upload_items) == 1
dbx = dropbox.Dropbox(os.getenv("DROPBOX_ACCESS_TOKEN"))
package = package_data["PACKAGE_NAME_PRETTY"]
version = package_data["PACKAGE_VERSION"]
for item in upload_items:
upload(dbx, package, version, os.path.join(dist_dir, item))
if __name__ == "__main__":
main()

6
fsbuild/version Executable file
View file

@ -0,0 +1,6 @@
#!/bin/sh
# This file is automatically generated by fs-package
set -e
python3 fsbuild/version.py "$@"

301
fsbuild/version.py Normal file
View file

@ -0,0 +1,301 @@
#!/usr/bin/env python3
# This file is automatically generated by fs-package
import datetime
import locale
import os
import re
import subprocess
import sys
class Version:
def __init__(self, version):
self.version = version
m = re.match("([0-9.]+[0-9])(.*)", version)
parts = m.group(1).split(".")
assert 2 <= len(parts) <= 4
self.major = int(parts[0])
self.minor = int(parts[1])
if len(parts) > 3:
self.build = int(parts[3])
else:
self.build = None
if len(parts) > 2:
self.revision = int(parts[2])
else:
self.revision = 0
self.tag = m.group(2)
self.commit = ""
def set_last(self, n):
if self.build is not None:
self.build = n
else:
self.revision = n
def __str__(self):
numbers = [self.major, self.minor, self.revision]
if self.build is not None:
numbers.append(self.build)
version = ".".join(str(x) for x in numbers)
return version + self.tag
def shell(command):
return subprocess.check_output(command, shell=True).decode("UTF-8")
def num_commits_since(base):
to = "HEAD"
result = int(
subprocess.check_output(
["git", "rev-list", f"{base}..{to}", "--count"]
).decode()
)
return result
def find_last_commit_for_file(path):
commit = subprocess.check_output(
["git", "log", "-n", "1", "--pretty=format:%H", "--", path]
).decode()
return commit
def find_last_commit():
commit = subprocess.check_output(
["git", "log", "-n", "1", "--pretty=format:%H"]
).decode()
return commit
def update_configure_ac(version, commit=""):
print("Updating configure.ac")
lines = []
with open("configure.ac", "r", encoding="UTF-8") as f:
for line in f:
if line.startswith("m4_define([fsbuild_version"):
if "_major" in line:
k = "FSBUILD_VERSION_MAJOR"
v = version.major
d = "Major version"
elif "_minor" in line:
k = "FSBUILD_VERSION_MINOR"
v = version.minor
d = "Minor version"
elif "_revision" in line:
k = "FSBUILD_VERSION_REVISION"
v = version.revision
d = "Revision"
else:
k = "FSBUILD_VERSION"
v = str(version)
d = "Full version"
line = "m4_define([{}], [{}])\n".format(k.lower(), v)
# if line.startswith("AC_DEFINE_UNQUOTED([FSBUILD_VERSION"):
# if "_MAJOR" in line:
# k = "FSBUILD_VERSION_MAJOR"
# v = version.major
# d = "Major version"
# elif "_MINOR" in line:
# k = "FSBUILD_VERSION_MINOR"
# v = version.minor
# d = "Minor version"
# elif "_REVISION" in line:
# k = "FSBUILD_VERSION_REVISION"
# v = version.revision
# d = "Revision"
# else:
# k = "FSBUILD_VERSION"
# v = str(version)
# d = "Full version"
# line = "AC_DEFINE_UNQUOTED([{}], [{}], [{}])\n".format(k, v, d)
if line.startswith("m4_define([fsbuild_commit"):
line = "m4_define([{}], [{}])\n".format(
"fsbuild_commit", commit
)
# if line.startswith("AC_DEFINE_UNQUOTED([FSBUILD_COMMIT"):
# k = "FSBUILD_COMMIT"
# v = commit
# d = "Package commit"
# line = "AC_DEFINE_UNQUOTED([{}], [{}], [{}])\n".format(k, v, d)
lines.append(line)
with open("configure.ac", "w", encoding="UTF-8") as f:
for line in lines:
f.write(line)
def update_debian_changelog(version):
print("Updating debian/changelog")
lines = []
first_line = True
first_line_changed = False
deb_package = "unknown"
deb_version = str(version)
# deb_version = deb_version.replace("alpha", "~alpha")
# deb_version = deb_version.replace("beta", "~beta")
# deb_version = deb_version.replace("dev", "~dev")
with open("debian/changelog", "r", encoding="UTF-8") as f:
for line in f:
if first_line:
first_line = False
deb_package = line.split(" ", 1)[0]
lines.append(
"{} ({}-0) unstable; urgency=low\n".format(
deb_package, deb_version
)
)
if lines[-1] != line:
first_line_changed = True
elif line.startswith(" -- ") and first_line_changed:
# Only update date if version was changed
author, date = line.split(" ")
date = datetime.datetime.now().strftime(
"%a, %e %b %Y %H:%M:%S %z"
)
lines.append("{} {}\n".format(author, date))
else:
lines.append(line)
with open("debian/changelog", "w", encoding="UTF-8") as f:
for line in lines:
f.write(line)
def update_spec_file(path, version):
print("Updating", path)
lines = []
rpm_version = str(version)
# rpm_version = rpm_version.replace("alpha", "-0.1alpha")
# rpm_version = rpm_version.replace("beta", "-0.1~beta")
# rpm_version = rpm_version.replace("dev", "-0.1dev")
# if not "-" in rpm_version:
# rpm_version += "-1"
with open(path, "r", encoding="UTF-8") as f:
for line in f:
if line.startswith("%define fsbuild_version "):
lines.append(
"%define fsbuild_version {}\n".format(rpm_version)
)
# elif line.startswith("%define unmangled_version "):
# lines.append("%define unmangled_version {0}\n".format(version))
else:
lines.append(line)
with open(path, "w", newline="\n") as f:
f.write("".join(lines))
def update_package_fs(version):
print("Updating PACKAGE.FS")
lines = []
with open("PACKAGE.FS", "r", encoding="UTF-8") as f:
for line in f:
if line.startswith("PACKAGE_VERSION="):
lines.append(f"PACKAGE_VERSION={str(version)}\n")
elif line.startswith("PACKAGE_VERSION_MAJOR="):
lines.append(f"PACKAGE_VERSION_MAJOR={str(version.major)}\n")
elif line.startswith("PACKAGE_VERSION_MINOR="):
lines.append(f"PACKAGE_VERSION_MINOR={str(version.minor)}\n")
elif line.startswith("PACKAGE_VERSION_REVISION="):
lines.append(
f"PACKAGE_VERSION_REVISION={str(version.revision)}\n"
)
elif line.startswith("PACKAGE_VERSION_TAG="):
lines.append(f"PACKAGE_VERSION_TAG={str(version.tag)}\n")
elif line.startswith("PACKAGE_COMMIT="):
lines.append(f"PACKAGE_COMMIT={version.commit}\n")
else:
lines.append(line)
with open("PACKAGE.FS", "w", newline="\n") as f:
f.write("".join(lines))
def update_version_fs(version):
print("Updating VERSION.FS")
with open("VERSION.FS", "w") as f:
f.write(str(version))
f.write("\n")
def update_commit_fs(version):
print("Updating COMMIT.FS")
with open("COMMIT.FS", "w") as f:
if version.commit:
f.write(version.commit)
f.write("\n")
def calculate_version(
auto_revision=False, increment_revision=False, include_commit=False
):
# with open("fsbuild/VERSION") as f:
# # with open("VERSION.FS") as f:
# version_str = f.read().strip()
with open("PACKAGE.FS") as f:
for line in f:
if line.startswith("PACKAGE_VERSION="):
version_str = line[16:].strip()
version = Version(version_str)
if auto_revision:
# version_commit = find_last_commit_for_file("VERSION.FS")
version_commit = find_last_commit_for_file("PACKAGE.FS")
increment = num_commits_since(version_commit)
if increment_revision:
increment += 1
if version.build is not None:
version.build += increment
else:
version.revision += increment
if "--commit" in sys.argv:
version.commit = find_last_commit()
return version
def update_version(version):
if os.path.exists("VERSION.FS"):
update_version_fs(version)
if os.path.exists("COMMIT.FS"):
update_commit_fs(version)
if os.path.exists("configure.ac"):
update_configure_ac(version)
if os.path.exists("debian/changelog"):
update_debian_changelog(version)
if os.path.exists("PACKAGE.FS"):
update_package_fs(version)
for filename in os.listdir("."):
if filename.endswith(".spec"):
update_spec_file(filename, version)
def main():
# For date/time formatting
locale.setlocale(locale.LC_TIME, "C")
auto_revision = "--auto" in sys.argv
increment_revision = "--next" in sys.argv
include_commit = "--commit" in sys.argv
# if "--auto-next" in sys.argv:
# auto_revision = True
# increment_revision = True
version = calculate_version(
auto_revision=auto_revision,
increment_revision=increment_revision,
include_commit=include_commit,
)
for arg in sys.argv:
if arg.startswith("--build="):
version.build = int(arg[8:])
elif arg.startswith("--revision="):
version.revision = int(arg[11:])
elif arg.startswith("--last="):
version.set_last(int(arg[7:]))
print(str(version))
if "--update" in sys.argv:
update_version(version)
if __name__ == "__main__":
main()

4
fsdeps/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
# fsdeps/.gitignore
# This file is automatically generated by fs-package
_*/

4
fsdeps/bashrc Normal file
View file

@ -0,0 +1,4 @@
# Intended for sourcing by other shell scripts
# This file is automatically generated by fs-package
export PS1='(fsdeps/use) \w \$ '

37
fsdeps/build Executable file
View file

@ -0,0 +1,37 @@
#!/bin/sh
# This file is automatically generated by fs-package
set -e
echo "Build dependencies"
echo -------------------------------------------------------------------------\
-------
. fsdeps/env.sh
. fsdeps/system.sh
echo FSDEPS_PREFIX=$FSDEPS_PREFIX
echo LIBRARY_PATH=$LIBRARY_PATH
echo PKG_CONFIG_PATH=$PKG_CONFIG_PATH
if [ $SYSTEM_OS = "macOS" ]; then
echo MACOSX_DEPLOYMENT_TARGET=$MACOSX_DEPLOYMENT_TARGET
fi
if [ -f fsdeps/build.sh ]; then
sh fsdeps/build.sh
elif [ -f ./deps.sh ]; then
sh ./deps.sh
fi
if [ $SYSTEM_OS = "Windows" ]; then
if [ -d $FSDEPS_PREFIX/bin ]; then
# Copy DLL files to root directory for running executables during development
echo "cp $FSDEPS_PREFIX/bin/*.dll ."
cp $FSDEPS_PREFIX/bin/*.dll .
fi
fi
echo -------------------------------------------------------------------------\
-------
echo "Built fsdeps for ${SYSTEM_OS}_${SYSTEM_ARCH}"

5
fsdeps/build.sh Normal file
View file

@ -0,0 +1,5 @@
#!/bin/sh
set -e
echo "No dependencies"

7
fsdeps/clean Executable file
View file

@ -0,0 +1,7 @@
#!/bin/sh
# This file is automatically generated by fs-package
set -e
. fsdeps/dep.sh
rm -Rf $FSDEPS_PREFIX

21
fsdeps/dep.sh Normal file
View file

@ -0,0 +1,21 @@
# Intended for sourcing by other shell scripts
# This file is automatically generated by fs-package
. fsdeps/env.sh
. fsdeps/system.sh
export PREFIX="$FSDEPS_PREFIX"
export REINSTALL="$FSDEPS_REINSTALL"
export INSTALLED="$PREFIX/installed/$PACKAGE-$REVISION"
mkdir -p $PREFIX/installed
if test -e $INSTALLED ; then
if [ "$REINSTALL" != "1" ]; then
echo "$INSTALLED"
exit 0
fi
fi
echo
echo $PACKAGE

47
fsdeps/download.py Normal file
View file

@ -0,0 +1,47 @@
#!/usr/bin/env python3
# This file is automatically generated by fs-package
import hashlib
import os
import sys
url = sys.argv[1]
checksum = sys.argv[2]
if checksum.startswith("sha256:"):
h = hashlib.sha256
checksum = checksum[7:]
else:
raise Exception("Unknown hash function")
def verify():
with open(archive, "rb") as f:
actual_checksum = h(f.read()).hexdigest()
result = actual_checksum == checksum
if result:
print("Checksum verified")
else:
print("Checksum verification failed")
print("Expected", checksum)
print("But got:", actual_checksum)
return result
archive = url.split("/")[-1]
if not os.path.exists("fsdeps/_sources"):
os.makedirs("fsdeps/_sources")
archive = os.path.join("fsdeps/_sources", archive)
if os.path.exists(archive):
if verify():
sys.exit(0)
print("Removing archive", archive)
os.remove(archive)
# FIXME: Replace use of wget, just use python instead
if os.system(f"cd fsdeps/_sources && wget {url}") != 0:
print("Failed to download")
sys.exit(1)
if not verify():
sys.exit(2)

18
fsdeps/env.sh Normal file
View file

@ -0,0 +1,18 @@
# Intended for sourcing by other shell scripts
# This file is automatically generated by fs-package
# export FSDEPS_NAME=project-name
# export FSDEPS_PREFIX=$HOME/.fsdeps/$FSDEPS_NAME
export FSDEPS_PREFIX="`pwd`/fsdeps/_prefix"
export CMAKE_PREFIX_PATH=$FSDEPS_PREFIX
export C_INCLUDE_PATH=$FSDEPS_PREFIX/include
export CPLUS_INCLUDE_PATH=$FSDEPS_PREFIX/include
export LIBRARY_PATH=$FSDEPS_PREFIX/lib
export PKG_CONFIG_PATH=$FSDEPS_PREFIX/lib/pkgconfig
export PATH=$FSDEPS_PREFIX/bin:$PATH
export LD_LIBRARY_PATH=$FSDEPS_PREFIX/lib:$FSDEPS_PREFIX/lib64
export MACOSX_DEPLOYMENT_TARGET=10.9

6
fsdeps/make Executable file
View file

@ -0,0 +1,6 @@
#!/bin/sh
# This file is automatically generated by fs-package
set -e
fsdeps/build

7
fsdeps/rebuild Executable file
View file

@ -0,0 +1,7 @@
#!/bin/sh
# This file is automatically generated by fs-package
set -e
fsdeps/clean
fsdeps/make

17
fsdeps/replace.py Normal file
View file

@ -0,0 +1,17 @@
#!/usr/bin/env python3
# This file is automatically generated by fs-package
import os
import sys
if len(sys.argv) > 4:
max = int(sys.argv[4])
else:
max = 999
stat = os.stat(sys.argv[1])
with open(sys.argv[1], "rb") as f:
data = f.read().decode("UTF-8")
data = data.replace(sys.argv[2], sys.argv[3], max)
with open(sys.argv[1], "wb") as f:
f.write(data.encode("UTF-8"))
os.utime(sys.argv[1], (stat.st_atime, stat.st_mtime))

15
fsdeps/system.sh Normal file
View file

@ -0,0 +1,15 @@
# Intended for sourcing by other shell scripts
# This file is automatically generated by fs-package
case "`uname`" in
Linux*) SYSTEM_OS=Linux;;
Darwin*) SYSTEM_OS=macOS;;
MINGW*) SYSTEM_OS=Windows;;
*) SYSTEM_OS=Unknown;;
esac
# FIXME: Remove hardcoded value
SYSTEM_ARCH=x86-64
# FIXME: Deprecated alias
SYSTEM=$SYSTEM_OS

14
fsdeps/use Executable file
View file

@ -0,0 +1,14 @@
#!/bin/sh
# This file is automatically generated by fs-package
set -e
. fsdeps/env.sh
COMMAND=$1
if [ "$COMMAND" = "" ]; then
exec bash --rcfile fsdeps/bashrc
else
shift
$COMMAND "$@"
fi

View file

@ -1,21 +0,0 @@
#!/usr/bin/env python3
import os
import sys
magics = [b"MZ\x90\x00", b"\x7fELF", b"\xcf\xfa\xed\xfe"]
def run(directory):
for dir_path, dir_names, file_names in os.walk(directory):
for file_name in file_names:
path = os.path.join(dir_path, file_name)
with open(path, "rb") as f:
magic = f.read(4)
if magic not in magics:
continue
print("Stripping", path)
assert os.system("strip {}".format(path)) == 0
if __name__ == "__main__":
run(sys.argv[1])