diff --git a/SConscript b/SConscript
index acd10e5..531f5d4 100644
--- a/SConscript
+++ b/SConscript
@@ -1,5 +1,6 @@
import copy
+import enum
import glob
import inspect
import json
@@ -9,6 +10,10 @@ import sys
import time
+class TargetType(enum.Enum):
+ PROGRAM = 0
+ LIBRARY = 1
+
class _VersionSpec:
minimum_version = None
maximum_version = None
@@ -31,6 +36,8 @@ class _Dependency:
cook_result: dict = {}
class _Target:
+ name: str
+ target_type: TargetType
builder = None
args: list = []
kwargs: dict = {}
@@ -192,7 +199,7 @@ def _find_lib(env: Environment, name: str, paths: 'list[str]', type : str = 'sta
def _error(env: Environment, message: str):
print(message, file=sys.stderr)
- env.Exit(1)
+ Exit(1)
def _try_merge_dicts(dictA: dict, dictB: dict) -> 'dict|None':
result = {}
@@ -316,7 +323,7 @@ def _find_version(env: Environment, dependency: _Dependency):
print(f'Required version: {dependency.version_spec}')
raise Exception(f'Could not find a suitable version for dependency {dependency.name}.')
-def _wrap_builder(builder, is_lib: bool = False):
+def _wrap_builder(builder, target_type: TargetType):
def _wrapped(env, dependencies = {}, *args, **kwargs):
target_dependencies = []
for name, version_spec in dependencies.items():
@@ -343,6 +350,15 @@ def _wrap_builder(builder, is_lib: bool = False):
kwargs['source'] = new_source
target = _Target()
+ if 'name' in kwargs:
+ target.name = kwargs['name']
+ else:
+ trgt = _target_entry(kwargs.get('target'))
+ if trgt is not None:
+ target.name = str(_target_entry(kwargs['target']).name)
+ else:
+ target.name = 'Unknown target'
+ target.target_type = target_type
target.builder = builder
target.args = args
target.kwargs = kwargs
@@ -396,6 +412,10 @@ def _version_to_string(version) -> str:
return '.'.join([str(v) for v in version])
def _finalize(env: Environment):
+ if generate_project:
+ _generate_project(generate_project)
+ Exit(0)
+
version_requirements = {dep.name: {
'min': dep.version_spec.minimum_version and _version_to_string(dep.version_spec.minimum_version),
'max': dep.version_spec.maximum_version and _version_to_string(dep.version_spec.maximum_version),
@@ -441,6 +461,73 @@ def _find_system_cache_dir() -> str:
# fallback
return _get_fallback_cache_dir()
+def _target_entry(target_value):
+ if target_value is None:
+ return None
+ if not isinstance(target_value, list):
+ target_value = [target_value]
+ if len(target_value) < 1:
+ return None
+ if isinstance(target_value[0], str):
+ target_value[0] = env.Entry(target_value[0])
+ return target_value[0]
+
+def _generate_project(project_type: str) -> None:
+ source_folder, target_folder = {
+ 'clion': (os.path.join(_spp_dir.abspath, 'util', 'clion_project_template'), Dir('#.idea').abspath)
+ }.get(project_type, (None, None))
+ if not source_folder:
+ _error(None, 'Invalid project type option.')
+
+ import uuid
+ def _generate_uuid() -> str:
+ return str(uuid.uuid4())
+
+ import pathlib
+ import shutil
+ import multiprocessing
+
+ root_path = pathlib.Path(env.Dir('#').abspath)
+ def _get_executables() -> list:
+ result = []
+ for target in env['SPP_TARGETS']:
+ if target.target_type == TargetType.PROGRAM:
+ trgt = _target_entry(target.kwargs['target'])
+ exe_path = pathlib.Path(trgt.abspath).relative_to(root_path)
+ result.append({
+ 'name': target.name,
+ 'filename': str(exe_path)
+ })
+ return result
+
+ import jinja2
+ jinja_env = jinja2.Environment()
+ jinja_env.globals['generate_uuid'] = _generate_uuid
+ jinja_env.globals['project'] = {
+ 'name': config['PROJECT_NAME'],
+ 'executables': _get_executables(),
+ 'build_types': ['debug', 'release_debug', 'release', 'profile']
+ }
+ jinja_env.globals['scons_exe'] = env['ENV']['_']
+ jinja_env.globals['nproc'] = multiprocessing.cpu_count()
+
+ source_path = pathlib.Path(source_folder)
+ target_path = pathlib.Path(target_folder)
+
+ for source_file in source_path.rglob('*'):
+ if source_file.is_file():
+ target_file = target_path / (source_file.relative_to(source_path))
+ target_file.parent.mkdir(parents=True, exist_ok=True)
+ if source_file.suffix != '.jinja':
+ shutil.copyfile(source_file, target_file)
+ continue
+ with source_file.open('r') as f:
+ templ = jinja_env.from_string(f.read())
+ target_file = target_file.with_suffix('')
+ with target_file.open('w') as f:
+ f.write(templ.render())
+
+
Import('config')
if not config.get('PROJECT_NAME'):
@@ -520,6 +607,17 @@ AddOption(
action = 'store_true'
)
+AddOption(
+ '--generate_project',
+ dest = 'generate_project',
+ type = 'choice',
+ choices = ('clion',),
+ nargs = 1,
+ action = 'store'
+)
+
+_spp_dir = Dir('.')
+
build_type = GetOption('build_type')
unity_mode = GetOption('unity_mode')
variant = GetOption('variant')
@@ -528,6 +626,7 @@ config_file = GetOption('config_file')
compiler = GetOption('compiler')
update_repositories = GetOption('update_repositories')
dump_env = GetOption('dump_env')
+generate_project = GetOption('generate_project')
default_CC = {
'gcc': 'gcc',
@@ -756,17 +855,17 @@ env.AddMethod(_make_interface, 'MakeInterface')
env.AddMethod(_lib_filename, 'LibFilename')
env.AddMethod(_find_lib, 'FindLib')
env.AddMethod(_error, 'Error')
-env.AddMethod(_wrap_builder(env.Library, is_lib = True), 'Library')
-env.AddMethod(_wrap_builder(env.StaticLibrary, is_lib = True), 'StaticLibrary')
-env.AddMethod(_wrap_builder(env.SharedLibrary, is_lib = True), 'SharedLibrary')
-env.AddMethod(_wrap_builder(env.Program), 'Program')
+env.AddMethod(_wrap_builder(env.Library, TargetType.LIBRARY), 'Library')
+env.AddMethod(_wrap_builder(env.StaticLibrary, TargetType.LIBRARY), 'StaticLibrary')
+env.AddMethod(_wrap_builder(env.SharedLibrary, TargetType.LIBRARY), 'SharedLibrary')
+env.AddMethod(_wrap_builder(env.Program, TargetType.PROGRAM), 'Program')
env.AddMethod(_wrap_default(env.Default), 'Default')
env.AddMethod(_wrap_depends(env.Depends), 'Depends')
-env.AddMethod(_wrap_builder(env.UnityProgram), 'UnityProgram')
-env.AddMethod(_wrap_builder(env.UnityLibrary, is_lib = True), 'UnityLibrary')
-env.AddMethod(_wrap_builder(env.UnityStaticLibrary, is_lib = True), 'UnityStaticLibrary')
-env.AddMethod(_wrap_builder(env.UnitySharedLibrary, is_lib = True), 'UnitySharedLibrary')
+env.AddMethod(_wrap_builder(env.UnityProgram, TargetType.PROGRAM), 'UnityProgram')
+env.AddMethod(_wrap_builder(env.UnityLibrary, TargetType.LIBRARY), 'UnityLibrary')
+env.AddMethod(_wrap_builder(env.UnityStaticLibrary, TargetType.LIBRARY), 'UnityStaticLibrary')
+env.AddMethod(_wrap_builder(env.UnitySharedLibrary, TargetType.LIBRARY), 'UnitySharedLibrary')
env.AddMethod(_module, 'Module')
env.AddMethod(_finalize, 'Finalize')
@@ -780,5 +879,6 @@ if dump_env:
print('==== Begin Environment Dump =====')
print(env.Dump())
print('==== End Environment Dump =====')
+ Exit(0)
Return('env')
diff --git a/requirements.txt b/requirements.txt
index 0fdee4b..51e32bb 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,3 @@
GitPython
psutil
+Jinja2
diff --git a/util/clion_project_template/.gitignore b/util/clion_project_template/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/util/clion_project_template/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/util/clion_project_template/customTargets.xml.jinja b/util/clion_project_template/customTargets.xml.jinja
new file mode 100644
index 0000000..598afbc
--- /dev/null
+++ b/util/clion_project_template/customTargets.xml.jinja
@@ -0,0 +1,20 @@
+
+
+
+ {% for executable in project.executables %}
+ {% for build_type in project.build_types %}
+ {% set build_type_name = build_type | capitalize -%}
+
+
+
+
+
+
+
+
+
+
+ {% endfor %}
+ {% endfor %}
+
+
diff --git a/util/clion_project_template/misc.xml b/util/clion_project_template/misc.xml
new file mode 100644
index 0000000..8067168
--- /dev/null
+++ b/util/clion_project_template/misc.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/util/clion_project_template/tools/External Tools.xml.jinja b/util/clion_project_template/tools/External Tools.xml.jinja
new file mode 100644
index 0000000..b6e2606
--- /dev/null
+++ b/util/clion_project_template/tools/External Tools.xml.jinja
@@ -0,0 +1,21 @@
+
+ {% for executable in project.executables %}
+ {% for build_type in project.build_types %}
+ {% set build_type_name = build_type | capitalize -%}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {% endfor %}
+ {% endfor %}
+
diff --git a/util/clion_project_template/vcs.xml b/util/clion_project_template/vcs.xml
new file mode 100644
index 0000000..b408360
--- /dev/null
+++ b/util/clion_project_template/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/util/clion_project_template/workspace.xml.jinja b/util/clion_project_template/workspace.xml.jinja
new file mode 100644
index 0000000..b1239fc
--- /dev/null
+++ b/util/clion_project_template/workspace.xml.jinja
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ "associatedIndex": 5
+}
+
+
+
+
+
+
+ {% for executable in project.executables -%}
+ {% for build_type in project.build_types -%}
+ {% set build_type_name = build_type | capitalize -%}
+
+
+
+
+
+ {% endfor %}
+ {% endfor %}
+
+
+
+
+
+