From b17f07b8547c9c3060359dcbe04545694a7fc5f1 Mon Sep 17 00:00:00 2001 From: Sammy Plat Date: Sun, 26 Dec 2021 14:35:43 +0100 Subject: [PATCH] Using SCons tools (#977) Changing the SCons architecture to clean up SConstruct and isolating languages more --- SConstruct | 61 +++++++++++++------ builders/cargo.py | 41 +++++++++++++ builders/coconut.py | 40 ++++++++++++ builders/go.py | 37 +++++++++++ builders/rustc.py | 45 ++++++++++++++ .../stacks_and_queues/code/rust/SConscript | 6 +- sconscripts/rust_SConscript | 2 +- 7 files changed, 209 insertions(+), 23 deletions(-) create mode 100644 builders/cargo.py create mode 100644 builders/coconut.py create mode 100644 builders/go.py create mode 100644 builders/rustc.py diff --git a/SConstruct b/SConstruct index 4182d9c5a..9546883d3 100644 --- a/SConstruct +++ b/SConstruct @@ -11,26 +11,51 @@ from pathlib import Path from collections import namedtuple import os - -rust_cargo_builder = Builder(action=['cargo build --bins --manifest-path $MANIFEST', - Move('$TARGET$PROGSUFFIX', '$SOURCE_DIR/target/debug/main$PROGSUFFIX')]) - -rust_rustc_builder = Builder(action='rustc $SOURCE -o $TARGET$PROGSUFFIX') - -go_builder = Builder(action='go build -o $TARGET$PROGSUFFIX $SOURCE') +import SCons +SCons.Warnings.warningAsException() # For interpreted languages to copy to build directory copy_builder = Builder(action=Copy('$TARGET', '$SOURCE')) -coconut_builder = Builder(action='coconut $COCONUTFLAGS $SOURCE $TARGET', src_suffix='.coco', target_suffix='.py') - env = Environment(ENV=os.environ, - BUILDERS={'rustc': rust_rustc_builder, - 'cargo': rust_cargo_builder, - 'Go': go_builder, - 'Copier': copy_builder, - 'Coconut': coconut_builder}, - tools=['gcc', 'gnulink', 'g++', 'gas', 'gfortran', 'javac']) + BUILDERS={'Copier': copy_builder}, + tools=[ + 'g++', 'gas', 'gcc', 'gfortran', 'gnulink', 'javac'], + toolpath=['builders']) + +available_languages = { + 'asm-x64', + 'bash', + 'c', + 'cpp', + 'fortran', + 'java', + 'julia', + 'lolcode' + 'lua', + 'php', + 'powershell', + 'python', + 'ruby', + 'viml', +} + +languages_to_import = { + 'coconut': ['coconut'], + 'go': ['go'], + 'rust': ['rustc', 'cargo'], +} + +for language, tools in languages_to_import.items(): + for tool in tools: + try: + env.Tool(tool) + except SCons.Warnings.SConsWarning as w: + print(f'{w.args[0][0]}, ignoring') + break + else: + available_languages.add(language) + Export('env') @@ -69,11 +94,11 @@ env.CPlusPlus = env.Program env.X64 = env.Program env.Fortran = env.Program -for language in languages: +for language in available_languages: Alias(language, f'#/build/{language}') sconscripts = [] -files_to_compile = {language: [] for language in languages} +files_to_compile = {language: [] for language in languages if language in available_languages} FileInformation = namedtuple('FileInformation', ['path', 'chapter', 'language']) @@ -85,7 +110,7 @@ for chapter_dir in contents_path.iterdir(): extended_chapter_path = code_dir.relative_to(contents_path).parent for language_dir in code_dir.iterdir(): - if (language := language_dir.stem) in languages: + if (language := language_dir.stem) in available_languages: new_files = [FileInformation(path=file_path, chapter=extended_chapter_path, language=language) diff --git a/builders/cargo.py b/builders/cargo.py new file mode 100644 index 000000000..0ac22e086 --- /dev/null +++ b/builders/cargo.py @@ -0,0 +1,41 @@ +from SCons.Builder import Builder +from SCons.Script import Move +import SCons.Util + +class ToolCargoWarning(SCons.Warnings.SConsWarning): + pass + +class CargoNotFound(ToolCargoWarning): + pass + +SCons.Warnings.enableWarningClass(ToolCargoWarning) + +def _detect(env): + try: + return env['cargo'] + except KeyError: + pass + + cargo = env.WhereIs('cargo') + if cargo: + return cargo + + SCons.Warnings.warn(CargoNotFound, 'Could not detect cargo') + +def exists(env): + return env.Detect('cargo') + + +def generate(env): + env['CARGO'] = _detect(env) + env['CARGOFLAGS'] = [] + env['MANIFEST'] = [] + + rust_cargo_builder = Builder( + action=['"$CARGO" build $CARGOFLAGS --bins --manifest-path $MANIFEST', + Move('$TARGET$PROGSUFFIX', + '$SOURCE_DIR/target/debug/main$PROGSUFFIX') + ], + suffix='$PROGSUFFIX', + ) + env.Append(BUILDERS={'cargo': rust_cargo_builder}) diff --git a/builders/coconut.py b/builders/coconut.py new file mode 100644 index 000000000..36498412b --- /dev/null +++ b/builders/coconut.py @@ -0,0 +1,40 @@ +from SCons.Builder import Builder +import SCons.Util + +class ToolCocoWarning(SCons.Warnings.SConsWarning): + pass + +class CoconutNotFound(ToolCocoWarning): + pass + +SCons.Warnings.enableWarningClass(ToolCocoWarning) + +def _detect(env): + try: + return env['coconut'] + except KeyError: + pass + + coconut = env.WhereIs('coconut') + if coconut: + return coconut + + SCons.Warnings.warn(CoconutNotFound, 'Could not find Coconut executable') + + +def generate(env): + env['COCONUT'] = _detect(env) + env['COCONUTFLAGS'] = [] + + coconut_compiler = Builder( + action='"$COCONUT" $COCONUTFLAGS $SOURCE $TARGET', + src_suffix='.coco', + suffix='.py', + ) + + env.Append(BUILDERS={'Coconut': coconut_compiler}) + +def exists(env): + return env.Detect('coconut') + + diff --git a/builders/go.py b/builders/go.py new file mode 100644 index 000000000..261789092 --- /dev/null +++ b/builders/go.py @@ -0,0 +1,37 @@ +from SCons.Builder import Builder +import SCons.Util + +class ToolGoWarning(SCons.Warnings.SConsWarning): + pass + +class GoNotFound(ToolGoWarning): + pass + +SCons.Warnings.enableWarningClass(ToolGoWarning) + +def _detect(env): + try: + return env['go'] + except KeyError: + pass + + go = env.WhereIs('go') + if go: + return go + + SCons.Warnings.warn(GoNotFound, 'Could not find go executable') + +def exists(env): + env.Detect('go') + +def generate(env): + env['GO'] = _detect(env) + env['GOFLAGS'] = [] + + go_builder = Builder( + action='"$GO" build -o $TARGET $GOFLAGS $SOURCE', + src_suffix='.go', + suffix='$PROGSUFFIX', + ) + + env.Append(BUILDERS={'Go': go_builder}) diff --git a/builders/rustc.py b/builders/rustc.py new file mode 100644 index 000000000..f07cf4fad --- /dev/null +++ b/builders/rustc.py @@ -0,0 +1,45 @@ +from SCons.Builder import Builder +import SCons.Util + +class ToolRustcWarning(SCons.Warnings.SConsWarning): + pass + +class RustcNotFound(ToolRustcWarning): + pass + +SCons.Warnings.enableWarningClass(ToolRustcWarning) + +def _detect(env): + try: + return env['rustc'] + except KeyError: + pass + + cargo = env.WhereIs('rustc') + if cargo: + return cargo + + SCons.Warnings.warn(RustcNotFound, 'Could not detect rustc') + + +def exists(env): + return env.Detect('rustc') + +def rustc_emitter(target, source, env): + src_name = str(source[0]) + pdb_name = src_name.replace(source[0].suffix, '.pdb') + env.SideEffect(pdb_name, target) + env.Clean(target, pdb_name) + return (target, source) + +def generate(env): + env['RUSTC'] = _detect(env) + env['RUSTCFLAGS'] = [] + + rust_cargo_builder = Builder( + action='"$RUSTC" $RUSTCFLAGS -o $TARGET $SOURCE', + suffix='$PROGSUFFIX', + src_suffix='.rs', + emitter=rustc_emitter, + ) + env.Append(BUILDERS={'rustc': rust_cargo_builder}) diff --git a/contents/stacks_and_queues/code/rust/SConscript b/contents/stacks_and_queues/code/rust/SConscript index 0c3f15913..343755fa8 100644 --- a/contents/stacks_and_queues/code/rust/SConscript +++ b/contents/stacks_and_queues/code/rust/SConscript @@ -3,8 +3,6 @@ from pathlib import Path dirname = Path.cwd().parents[1].stem -env.rustc(f'#/build/rust/stack', '#/contents/stacks_and_queues/code/rust/Stack.rs') -env.Clean('rust', f'#/build/rust/stack.pdb') +env.rustc(f'#/build/rust/{dirname}/stack', '#/contents/stacks_and_queues/code/rust/Stack.rs') -env.rustc(f'#/build/rust/queue', '#/contents/stacks_and_queues/code/rust/Queue.rs') -env.Clean('rust', f'#/build/rust/queue.pdb') \ No newline at end of file +env.rustc(f'#/build/rust/{dirname}/queue', '#/contents/stacks_and_queues/code/rust/Queue.rs') diff --git a/sconscripts/rust_SConscript b/sconscripts/rust_SConscript index d93b9d680..893877a67 100644 --- a/sconscripts/rust_SConscript +++ b/sconscripts/rust_SConscript @@ -12,4 +12,4 @@ for file_info in files_to_compile: build_result = env.rustc(build_target, str(file_info.path)) env.Clean('rust', f'{build_target}.pdb') - env.Alias(str(file_info.chapter), build_result) \ No newline at end of file + env.Alias(str(file_info.chapter), build_result)