Compare commits

..

16 Commits

Author SHA1 Message Date
1e4bb17251 Added recipe for json and updated yaml-cpp recipe. 2024-10-25 08:29:25 +02:00
c461b5da39 Added recipes for curl, libidn2, libpsl and libunistring. 2024-10-23 23:37:37 +02:00
b7cb5f7c48 Added openssl recipe. 2024-08-21 09:36:17 +02:00
9c64f982fd Added recipe for winsock2 and target_os to dependency conditions. 2024-08-19 18:36:37 +02:00
378c6ba341 Fixed Catch2 recipe. 2024-08-18 17:28:26 +02:00
96fc1984cd Fixed compilation with MSVC. 2024-08-18 17:28:25 +02:00
396350b295 Allow settings COMPILATIONDB_FILTER_FILES via config. 2024-08-18 17:26:32 +02:00
5de1ac4444 Enable experimental library features (jthread) for clang. 2024-08-18 17:26:30 +02:00
d5712120df Moved check of SYSTEM_CACHE_DIR accessibility to before it is used. 2024-08-18 17:25:59 +02:00
267d06a997 Added CXXFLAGS and CFLAGS to config variables. 2024-08-18 17:24:41 +02:00
089ea25c10 Adjusted error description to make more sense. 2024-08-17 18:11:36 +02:00
e1404fee58 Fixed zlib recipe on linux. 2024-08-17 18:11:13 +02:00
c4200393fb Fixed compilation with MSVC. 2024-08-15 15:27:39 +02:00
0c82036300 Update to new recipe system (S++ 2.0). 2024-08-14 23:33:04 +02:00
35b38b8b6e Some more work on the new dependency resolution system. 2024-08-08 14:32:28 +02:00
8bea4a6db5 Some tests. 2024-08-06 09:33:42 +02:00
11 changed files with 247 additions and 88 deletions

View File

@@ -1,7 +1,6 @@
import copy
import glob
import inspect
import json
import os
import psutil
@@ -12,15 +11,13 @@ import time
class _VersionSpec:
minimum_version = None
maximum_version = None
options = {}
def __init__(self, minimum_version = None, maximum_version = None, options = {}):
def __init__(self, minimum_version = None, maximum_version = None):
self.minimum_version = minimum_version
self.maximum_version = maximum_version
self.options = options
def __str__(self):
return f'Min: {self.minimum_version}, Max: {self.maximum_version}, Options: {self.options}'
return f'Min: {self.minimum_version}, Max: {self.maximum_version}'
class _Dependency:
name: str = ''
@@ -56,19 +53,12 @@ def _find_recipe(env: Environment, recipe_name: str):
env['SPP_RECIPES'][recipe_name] = recipe
return recipe
def _run_cook(dependency: _Dependency):
if not dependency.cook_result:
cook_signature = inspect.signature(dependency.recipe.cook)
kwargs = {}
if 'options' in cook_signature.parameters:
kwargs['options'] = dependency.version_spec.options
dependency.cook_result = dependency.recipe.cook(env, dependency.version, **kwargs)
def _cook(env: Environment, recipe_name: str):
dependency = env['SPP_DEPENDENCIES'].get(recipe_name)
if not dependency:
raise Exception(f'Cannot cook {recipe_name} as it was not listed as a dependency.')
_run_cook(dependency)
if not dependency.cook_result:
dependency.cook_result = dependency.recipe.cook(env, dependency.version)
return dependency.cook_result
def _module(env: Environment, file: str):
@@ -100,7 +90,8 @@ def _inject_dependency(dependency, kwargs: dict, add_sources: bool = True) -> No
for inner_dependency in dependency['DEPENDENCIES']:
_inject_dependency(inner_dependency, kwargs, False)
elif isinstance(dependency, _Dependency):
_run_cook(dependency)
if not dependency.cook_result:
dependency.cook_result = dependency.recipe.cook(env, dependency.version)
_inject_list(kwargs, dependency.cook_result, 'CPPPATH')
_inject_list(kwargs, dependency.cook_result, 'CPPDEFINES')
_inject_list(kwargs, dependency.cook_result, 'LIBPATH')
@@ -194,35 +185,8 @@ def _error(env: Environment, message: str):
print(message, file=sys.stderr)
env.Exit(1)
def _try_merge_dicts(dictA: dict, dictB: dict) -> 'dict|None':
result = {}
for key, valueA in dictA.items():
if key in dictB:
valueB = dictB[key]
if type(valueA) != type(valueB):
return None
elif type(valueA) == list:
result[key] = valueA + valueB
elif type(valueA) == dict:
mergedValue = _try_merge_dicts(valueA, valueB)
if mergedValue is None:
return None
result[key] = mergedValue
elif valueA != valueB:
return None
else:
result[key] = valueA
for key, valueB in dictB.items():
if key not in result:
result[key] = valueB
return result
def _find_common_depenency_version(name: str, versionA: _VersionSpec, versionB: _VersionSpec) -> _VersionSpec:
options = _try_merge_dicts(versionA.options, versionB.options)
if options is None:
return None
result_version = _VersionSpec(options=options)
result_version = _VersionSpec()
if versionA.minimum_version is not None:
if versionB.minimum_version is not None:
result_version.minimum_version = max(versionA.minimum_version, versionB.minimum_version)
@@ -245,7 +209,7 @@ def _find_common_depenency_version(name: str, versionA: _VersionSpec, versionB:
return result_version
def _parse_version_spec(version_spec: dict) -> _VersionSpec:
return _VersionSpec(version_spec.get('min'), version_spec.get('max'), version_spec.get('options', {}))
return _VersionSpec(version_spec.get('min'), version_spec.get('max'))
def _can_add_dependency(env: Environment, name: str, version_spec: _VersionSpec) -> bool:
if name not in env['SPP_DEPENDENCIES']:
@@ -292,11 +256,7 @@ def _version_matches(version, version_spec: _VersionSpec) -> bool:
def _find_version(env: Environment, dependency: _Dependency):
for update in (False, True):
versions_signature = inspect.signature(dependency.recipe.versions)
kwargs = {}
if 'options' in versions_signature.parameters:
kwargs['options'] = dependency.version_spec.options
versions = dependency.recipe.versions(env, update=update, **kwargs)
versions = dependency.recipe.versions(env, update=update)
_sort_versions(versions)
for version in versions:
if _version_matches(version, dependency.version_spec):
@@ -565,7 +525,6 @@ except:
env['CLONE_DIR'] = os.path.join(env['SYSTEM_CACHE_DIR'], 'cloned')
env['DOWNLOAD_DIR'] = os.path.join(env['SYSTEM_CACHE_DIR'], 'downloaded')
env['UPDATE_REPOSITORIES'] = update_repositories
env['CXX_STANDARD'] = config['CXX_STANDARD'] # make it available to everyone
env['DEPS_CFLAGS'] = []
env['DEPS_CXXFLAGS'] = []
@@ -675,6 +634,7 @@ if env['COMPILER_FAMILY'] == 'gcc' or env['COMPILER_FAMILY'] == 'clang':
# -Wtautological-compare triggers in libfmt and doesn't seem too useful anyway
env.Append(CCFLAGS = ['-Wno-missing-field-initializers', '-Wno-maybe-uninitialized'])
env.Append(CXXFLAGS = ['-Wno-subobject-linkage', '-Wno-dangling-reference', '-Wno-init-list-lifetime', '-Wno-tautological-compare'])
else: # clang only
# no-gnu-anonymous-struct - we don't care
env.Append(CCFLAGS = ['-Wno-gnu-anonymous-struct'])

View File

@@ -27,8 +27,12 @@ def _autotools_project(env: Environment, project_root: str, config_args: 'list[s
jobs = env.GetOption('num_jobs')
env = os.environ.copy()
env['CFLAGS'] = cflags
config_script = os.path.join(project_root, configure_script_path)
if not os.path.exists(config_script) and os.path.exists(f'{config_script}.ac'):
subprocess.run(('autoreconf', '--install', '--force'), cwd=project_root)
subprocess.run((os.path.join(project_root, configure_script_path), f'--prefix={install_dir}', *config_args), cwd=build_dir, env=env, stdout=sys.stdout, stderr=sys.stderr, check=True)
subprocess.run((config_script, f'--prefix={install_dir}', *config_args), cwd=build_dir, env=env, stdout=sys.stdout, stderr=sys.stderr, check=True)
subprocess.run(('make', f'-j{jobs}', *build_args), cwd=build_dir, stdout=sys.stdout, stderr=sys.stderr, check=True)
subprocess.run(('make', 'install', *install_args), cwd=build_dir, stdout=sys.stdout, stderr=sys.stderr, check=True)
pathlib.Path(install_dir, _BUILT_STAMPFILE).touch()

View File

@@ -2,6 +2,7 @@
from git import Repo
from git.exc import GitError
import hashlib
import re
from SCons.Script import *
Import('env')
@@ -55,9 +56,7 @@ def _git_recipe(env: Environment, globals: dict, repo_name, repo_url, cook_fn, v
_tag_pattern = _make_callable(tag_pattern)
versions_cb = versions and _make_callable(versions)
def _versions(env: Environment, update: bool = False, options: dict = {}):
if 'ref' in options:
return [(0, 0, 0)] # no versions if compiling from a branch
def _versions(env: Environment, update: bool = False):
pattern = _tag_pattern(env)
if pattern:
tags = env.GitTags(repo_name = _repo_name(env), remote_url = _repo_url(env), force_fetch=update)
@@ -77,10 +76,8 @@ def _git_recipe(env: Environment, globals: dict, repo_name, repo_url, cook_fn, v
def _dependencies(env: Environment, version) -> 'dict':
return dependencies
def _cook(env: Environment, version, options: dict = {}) -> dict:
if 'ref' in options:
git_ref = options['ref']
elif tag_fn:
def _cook(env: Environment, version) -> dict:
if tag_fn:
git_ref = f'refs/tags/{tag_fn(version)}'
else:
assert ref_fn

View File

@@ -1,13 +0,0 @@
diff --git a/cmake/GetGitRevisionDescription.cmake b/cmake/GetGitRevisionDescription.cmake
index a08895c64..d3873387d 100644
--- a/cmake/GetGitRevisionDescription.cmake
+++ b/cmake/GetGitRevisionDescription.cmake
@@ -143,7 +143,7 @@ function(get_git_head_revision _refspecvar _hashvar)
string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir
${worktree_ref})
string(STRIP ${git_worktree_dir} git_worktree_dir)
- _git_find_closest_git_dir("${git_worktree_dir}" GIT_DIR)
+ set(GIT_DIR "${git_worktree_dir}")
set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD")
endif()
else()

View File

@@ -6,32 +6,22 @@ from SCons.Script import *
def _git_cook(env: Environment, repo: dict) -> dict:
checkout_root = repo['checkout_root']
build_result = env.CMakeProject(project_root=checkout_root, generate_args = ['-DSDL_STATIC=ON', '-DSDL_SHARED=OFF'])
libs = []
if platform.system() == 'Windows':
if env['BUILD_TYPE'] == 'debug':
lib_names = ['SDL2-staticd', 'SDL3-staticd']
libs.append('SDL2-staticd')
else:
lib_names = ['SDL2-static', 'SDL3-static']
libs.append('SDL2-static')
libs.extend(('kernel32', 'user32', 'gdi32', 'winmm', 'imm32', 'ole32', 'oleaut32', 'version', 'uuid', 'advapi32', 'setupapi', 'shell32', 'dinput8'))
else:
if env['BUILD_TYPE'] == 'debug':
lib_names = ['SDL2d', 'SDL3']
libs.append('SDL2d')
else:
lib_names = ['SDL2', 'SDL3']
lib_file = None
is_sdl3 = False
for lib_name in lib_names:
lib_file = env.FindLib(lib_name, paths=build_result['LIBPATH'], allow_fail=True)
if lib_file:
is_sdl3 = "SDL3" in lib_name
break
if not lib_file:
env.Error('Could not find SDL lib file.')
libs.insert(0, lib_file)
libs.append('SDL2')
return {
'CPPPATH': [os.path.join(build_result['install_dir'], (is_sdl3 and 'include' or 'include/SDL2'))], # SDL is really weird about include paths ...
'LIBPATH': build_result['LIBPATH'],
'CPPPATH': [os.path.join(build_result['install_dir'], 'include/SDL2')], # SDL is really weird about include paths ...
'LIBS': libs
}

39
recipes/curl/recipe.py Normal file
View File

@@ -0,0 +1,39 @@
import re
from SCons.Script import *
def _build_lib_name(env: Environment) -> str:
if os.name == 'posix':
return {
'debug': 'curl-d'
}.get(env['BUILD_TYPE'], 'curl')
elif os.name == 'nt':
raise Exception('TODO')
else:
raise Exception('curl is not supported yet on this OS')
def _git_cook(env: Environment, repo: dict) -> dict:
checkout_root = repo['checkout_root']
build_result = env.CMakeProject(checkout_root, generate_args=['-DBUILD_CURL_EXE=OFF','-DBUILD_SHARED_LIBS=OFF',
'-DBUILD_STATIC_LIBS=ON', '-DHTTP_ONLY=ON',
'-DCURL_USE_LIBSSH2=OFF'])
lib_name = _build_lib_name(env)
return {
'CPPPATH': build_result['CPPPATH'],
'LIBS': [env.FindLib(lib_name, paths=build_result['LIBPATH'])],
}
env.GitRecipe(
globals = globals(),
repo_name = 'curl',
repo_url = 'https://github.com/curl/curl.git',
tag_pattern = re.compile(r'^curl-([0-9]+)_([0-9]+)_([0-9]+)$'),
tag_fn = lambda version: f'curl-{version[0]}_{version[1]}_{version[2]}',
cook_fn = _git_cook,
dependencies = {
'openssl': {},
'zlib': {},
'psl': {}
}
)

48
recipes/idn2/recipe.py Normal file
View File

@@ -0,0 +1,48 @@
import json
import os
import re
import requests
from SCons.Script import *
_VERSIONS_URL = 'https://gitlab.com/api/v4/projects/2882658/releases'
_VERSION_PATTERN = re.compile(r'^([0-9]+)\.([0-9]+)\.([0-9]+)$')
def versions(env: Environment, update: bool = False):
versions_file = os.path.join(env['DOWNLOAD_DIR'], 'libidn2_versions.json')
if update or not os.path.exists(versions_file):
req = requests.get(_VERSIONS_URL)
versions_data = json.loads(req.text)
result = []
for version_data in versions_data:
match = _VERSION_PATTERN.match(version_data['name'])
if not match:
continue
result.append((int(match.groups()[0]), int(match.groups()[1]), int(match.groups()[2])))
with open(versions_file, 'w') as f:
json.dump(result, f)
return result
else:
try:
with open(versions_file, 'r') as f:
return [tuple(v) for v in json.load(f)]
except:
print('libidn2_versions.json is empty or broken, redownloading.')
return versions(env, update=True)
def dependencies(env: Environment, version) -> 'dict':
return {
'unistring': {}
}
def cook(env: Environment, version) -> dict:
url = f'https://ftp.gnu.org/gnu/libidn/libidn2-{version[0]}.{version[1]}.{version[2]}.tar.gz'
repo = env.DownloadAndExtract(f'libidn2_{version[0]}.{version[1]}.{version[2]}', url = url, skip_folders = 1)
checkout_root = repo['extracted_root']
build_result = env.AutotoolsProject(checkout_root)
return {
'CPPPATH': build_result['CPPPATH'],
'LIBS': [env.FindLib('idn2', paths=build_result['LIBPATH'])]
}

22
recipes/json/recipe.py Normal file
View File

@@ -0,0 +1,22 @@
import re
from SCons.Script import *
def _git_cook(env: Environment, repo: dict) -> dict:
checkout_root = repo['checkout_root']
build_result = env.CMakeProject(project_root=checkout_root)
return {
'CPPPATH': build_result['CPPPATH']
}
env.GitRecipe(
globals = globals(),
repo_name = 'json',
repo_url = 'https://github.com/nlohmann/json.git',
tag_pattern = re.compile(r'^v([0-9]+)\.([0-9]+)\.([0-9]+)$'),
tag_fn = lambda version: f'v{version[0]}.{version[1]}.{version[2]}',
cook_fn = _git_cook
)

70
recipes/psl/recipe.py Normal file
View File

@@ -0,0 +1,70 @@
import json
import os
import re
import requests
from SCons.Script import *
_VERSIONS_URL = 'https://api.github.com/repos/rockdaboot/libpsl/releases'
_VERSION_PATTERN = re.compile(r'^Release v([0-9]+)\.([0-9]+)\.([0-9]+)$')
def versions(env: Environment, update: bool = False):
versions_file = os.path.join(env['DOWNLOAD_DIR'], 'libpsl_versions.json')
if update or not os.path.exists(versions_file):
req = requests.get(_VERSIONS_URL)
versions_data = json.loads(req.text)
result = []
for version_data in versions_data:
match = _VERSION_PATTERN.match(version_data['name'])
if not match:
continue
result.append((int(match.groups()[0]), int(match.groups()[1]), int(match.groups()[2])))
with open(versions_file, 'w') as f:
json.dump(result, f)
return result
else:
try:
with open(versions_file, 'r') as f:
return [tuple(v) for v in json.load(f)]
except:
print('libpsl_versions.json is empty or broken, redownloading.')
return versions(env, update=True)
def dependencies(env: Environment, version) -> 'dict':
return {
'idn2': {},
'unistring': {}
}
def cook(env: Environment, version) -> dict:
url = f'https://github.com/rockdaboot/libpsl/releases/download/{version[0]}.{version[1]}.{version[2]}/libpsl-{version[0]}.{version[1]}.{version[2]}.tar.gz'
repo = env.DownloadAndExtract(f'libpsl_{version[0]}.{version[1]}.{version[2]}', url = url, skip_folders = 1)
checkout_root = repo['extracted_root']
build_result = env.AutotoolsProject(checkout_root)
return {
'CPPPATH': build_result['CPPPATH'],
'LIBS': [env.FindLib('psl', paths=build_result['LIBPATH'])]
}
#def _git_cook(env: Environment, repo: dict) -> dict:
# checkout_root = repo['checkout_root']
# subprocess.run((os.path.join(checkout_root, 'autogen.sh'),), cwd=checkout_root)
# build_result = env.AutotoolsProject(checkout_root)
# return {
# 'CPPPATH': build_result['CPPPATH'],
# 'LIBS': [env.FindLib('psl', paths=build_result['LIBPATH'])]
# }
#
#env.GitRecipe(
# globals = globals(),
# repo_name = 'psl',
# repo_url = 'https://github.com/rockdaboot/libpsl.git',
# tag_pattern = re.compile(r'^libpsl-([0-9]+)\.([0-9]+)\.([0-9]+)$'),
# tag_fn = lambda version: f'libpsl-{version[0]}.{version[1]}.{version[2]}',
# cook_fn = _git_cook,
# dependencies = {
# 'idn2': {},
# 'unistring': {}
# }
#)

View File

@@ -0,0 +1,42 @@
import json
import os
import re
import requests
from SCons.Script import *
_VERSIONS_URL = 'https://ftp.gnu.org/gnu/libunistring/?F=0'
_VERSION_PATTERN = re.compile(r'href="libunistring-([0-9]+)\.([0-9]+)\.([0-9]+)\.tar\.gz"')
def versions(env: Environment, update: bool = False):
versions_file = os.path.join(env['DOWNLOAD_DIR'], 'libunistring_versions.json')
if update or not os.path.exists(versions_file):
req = requests.get(_VERSIONS_URL)
result = []
for match in _VERSION_PATTERN.finditer(req.text):
result.append((int(match.groups()[0]), int(match.groups()[1]), int(match.groups()[2])))
with open(versions_file, 'w') as f:
json.dump(result, f)
return result
else:
try:
with open(versions_file, 'r') as f:
return [tuple(v) for v in json.load(f)]
except:
print('libunistring_versions.json is empty or broken, redownloading.')
return versions(env, update=True)
def dependencies(env: Environment, version) -> 'dict':
return {}
def cook(env: Environment, version) -> dict:
url = f'https://ftp.gnu.org/gnu/libunistring/libunistring-{version[0]}.{version[1]}.{version[2]}.tar.gz'
repo = env.DownloadAndExtract(f'libunistring_{version[0]}.{version[1]}.{version[2]}', url = url, skip_folders = 1)
checkout_root = repo['extracted_root']
build_result = env.AutotoolsProject(checkout_root)
return {
'CPPPATH': build_result['CPPPATH'],
'LIBS': [env.FindLib('unistring', paths=build_result['LIBPATH'])]
}

View File

@@ -19,7 +19,7 @@ def _git_cook(env: Environment, repo: dict) -> dict:
env.GitRecipe(
globals = globals(),
repo_name = 'yaml-cpp',
repo_url = 'https://github.com/jbeder/yaml-cpp',
repo_url = 'https://github.com/jbeder/yaml-cpp.git',
tag_pattern = re.compile(r'^yaml-cpp-([0-9]+)\.([0-9]+)\.([0-9]+)$'),
tag_fn = lambda version: f'yaml-cpp-{version[0]}.{version[1]}.{version[2]}',
cook_fn = _git_cook