Skip to content
44 changes: 30 additions & 14 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ Currently, the aim is to provide a way to compile or copy the implementation fil
To run the compilation for all implementations in one language, e.g. C, run the command `scons build/c`, and the resulting executables will be available in the `build/c` directory, each in their respective algorithm directory, containing the executable."""

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')])

Expand All @@ -23,48 +25,62 @@ env = Environment(ENV=os.environ,
'Go': go_builder},
tools=['gcc', 'gnulink', 'g++', 'gas', 'gfortran'])

Export('env')

env['CFLAGS'] = '-Wall -Wextra -Werror'
env['CXXFLAGS'] = '-std=c++17'
env['ASFLAGS'] = '--64'

# Add other languages here when you want to add language targets
# Put 'name_of_language_directory' : 'file_extension'
languages = {
'c': 'c',
'c': 'c',
'cpp': 'cpp',
'asm-x64': 's',
'rust': 'rs',
'go': 'go',
'fortran': 'f90',
}

# Do not add new Builders here, add them to the BUILDERS argument in the call to Environment above
env.C = env.Program
env.CPlusPlus = env.Program
env.X64 = env.Program
env.Fortran = env.Program

Export('env')
for language in languages:
Alias(language, f'#/build/{language}')

sconscripts = []
files_to_compile = {language: [] for language in languages}

for chapter_dir in Path.cwd().joinpath('contents').iterdir():
if (code_dir := (chapter_dir / 'code')).exists():
for path in code_dir.iterdir():
if path.stem in languages:
# Check for overriding sconscript
if (sconscript_path := path / 'SConscript').exists():
sconscripts.append(sconscript_path)
SConscript(sconscript_path, exports='env')
FileInformation = namedtuple('FileInformation', ['path', 'chapter', 'language'])


contents_path = Path.cwd().joinpath('contents')
for chapter_dir in contents_path.iterdir():
for code_dir in chapter_dir.glob('**/code'):
# For nested chapters e.g. contents/convolutions/1d/
extended_chapter_path = code_dir.relative_to(contents_path).parent

for language_dir in code_dir.iterdir():
if (language := language_dir.stem) in languages:
new_files = [FileInformation(path=file_path,
chapter=extended_chapter_path,
language=language)
for file_path in language_dir.glob(f'**/*.{languages[language]}')
]
# Check for overriding SConscript
if (sconscript_path := language_dir / 'SConscript').exists():
SConscript(sconscript_path, exports={'files_to_compile': new_files})
else:
files_to_compile[path.stem].extend(path.glob(f'*.{languages[path.stem]}'))
files_to_compile[language].extend(new_files)

sconscript_dir_path = Path('sconscripts')
sconscript_dir_path = Path.cwd().joinpath('sconscripts')
for language, files in files_to_compile.items():
if files:
if (sconscript_path := sconscript_dir_path / f"{language}_SConscript").exists():
SConscript(sconscript_path, exports = {'files_to_compile': files,
'language': language})
SConscript(sconscript_path, exports = {'files_to_compile': files})
else:
print(f'{language} file found at {files[0]}, but no sconscript file is present ')

10 changes: 5 additions & 5 deletions contents/approximate_counting/code/c/SConscript
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Import('*')
from pathlib import Path
Import('files_to_compile env')

dirname = Path.cwd().parents[1].stem

env.C(f'#/build/c/{dirname}', Glob('*.c'), LIBS='m')
for file_info in files_to_compile:
build_target = f'#/build/{file_info.language}/{file_info.chapter}/{file_info.path.stem}'
build_result = env.C(build_target, str(file_info.path), LIBS='m')
env.Alias(str(file_info.chapter), build_result)
10 changes: 5 additions & 5 deletions contents/cooley_tukey/code/asm-x64/SConscript
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Import('*')
from pathlib import Path
Import('files_to_compile env')

dirname = Path.cwd().parents[1].stem

env.X64(f'#/build/asm-x64/{dirname}', Glob('*.s'), LIBS=['m'], LINKFLAGS='-no-pie')
for file_info in files_to_compile:
build_target = f'#/build/{file_info.language}/{file_info.chapter}/{file_info.path.stem}'
build_result = env.X64(build_target, str(file_info.path), LIBS='m', LINKFLAGS='-no-pie')
env.Alias(str(file_info.chapter), build_result)
10 changes: 5 additions & 5 deletions contents/cooley_tukey/code/c/SConscript
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Import('*')
from pathlib import Path
Import('files_to_compile env')

dirname = Path.cwd().parents[1].stem

env.C(f'#/build/c/{dirname}', Glob('*.c'), LIBS=['m', 'fftw3'])
for file_info in files_to_compile:
build_target = f'#/build/{file_info.language}/{file_info.chapter}/{file_info.path.stem}'
build_result = env.C(build_target, str(file_info.path), LIBS=['m', 'fftw3'])
env.Alias(str(file_info.chapter), build_result)
6 changes: 0 additions & 6 deletions contents/euclidean_algorithm/code/fortran/SConscript

This file was deleted.

10 changes: 5 additions & 5 deletions contents/forward_euler_method/code/asm-x64/SConscript
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Import('*')
from pathlib import Path
Import('files_to_compile env')

dirname = Path.cwd().parents[1].stem

env.X64(f'#/build/asm-x64/{dirname}', Glob('*.s'), LIBS='m', LINKFLAGS='-no-pie')
for file_info in files_to_compile:
build_target = f'#/build/{file_info.language}/{file_info.chapter}/{file_info.path.stem}'
build_result = env.X64(build_target, str(file_info.path), LIBS='m', LINKFLAGS='-no-pie')
env.Alias(str(file_info.chapter), build_result)
10 changes: 5 additions & 5 deletions contents/forward_euler_method/code/c/SConscript
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Import('*')
from pathlib import Path
Import('files_to_compile env')

dirname = Path.cwd().parents[1].stem

env.C(f'#/build/c/{dirname}', Glob('*.c'), LIBS='m')
for file_info in files_to_compile:
build_target = f'#/build/{file_info.language}/{file_info.chapter}/{file_info.path.stem}'
build_result = env.C(build_target, str(file_info.path), LIBS='m')
env.Alias(str(file_info.chapter), build_result)
10 changes: 5 additions & 5 deletions contents/graham_scan/code/c/SConscript
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Import('*')
from pathlib import Path
Import('files_to_compile env')

dirname = Path.cwd().parents[1].stem

env.C(f'#/build/c/{dirname}', Glob('*.c'), LIBS='m')
for file_info in files_to_compile:
build_target = f'#/build/{file_info.language}/{file_info.chapter}/{file_info.path.stem}'
build_result = env.C(build_target, str(file_info.path), LIBS='m')
env.Alias(str(file_info.chapter), build_result)
10 changes: 5 additions & 5 deletions contents/split-operator_method/code/c/SConscript
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Import('*')
from pathlib import Path
Import('files_to_compile env')

dirname = Path.cwd().parents[1].stem

env.C(f'#/build/c/{dirname}', Glob('*.c'), LIBS=['m', 'fftw3'])
for file_info in files_to_compile:
build_target = f'#/build/{file_info.language}/{file_info.chapter}/{file_info.path.stem}'
build_result = env.C(build_target, str(file_info.path), LIBS=['m', 'fftw3'])
env.Alias(str(file_info.chapter), build_result)
10 changes: 5 additions & 5 deletions contents/split-operator_method/code/cpp/SConscript
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Import('*')
from pathlib import Path
Import('files_to_compile env')

dirname = Path.cwd().parents[1].stem

env.CPlusPlus(f'#/build/cpp/{dirname}', Glob('*.cpp'), LIBS=['m', 'fftw3'])
for file_info in files_to_compile:
build_target = f'#/build/{file_info.language}/{file_info.chapter}/{file_info.path.stem}'
build_result = env.CPlusPlus(build_target, str(file_info.path), LIBS=['m', 'fftw3'])
env.Alias(str(file_info.chapter), build_result)
10 changes: 5 additions & 5 deletions sconscripts/asm-x64_SConscript
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Import('files_to_compile language env')
from pathlib import Path
Import('files_to_compile env')

for file in files_to_compile:
chapter_name = file.parent.parent.parent.stem
env.X64(f'#/build/{language}/{chapter_name}', str(file), LINKFLAGS='-no-pie')
for file_info in files_to_compile:
build_target = f'#/build/{file_info.language}/{file_info.chapter}/{file_info.path.stem}'
build_result = env.X64(build_target, str(file_info.path), LINKFLAGS='-no-pie')
env.Alias(str(file_info.chapter), build_result)
8 changes: 4 additions & 4 deletions sconscripts/c_SConscript
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Import('files_to_compile env')
from pathlib import Path

for file in files_to_compile:
chapter_name = file.parent.parent.parent.stem
env.C(f'#/build/c/{chapter_name}', str(file))
for file_info in files_to_compile:
build_target = f'#/build/{file_info.language}/{file_info.chapter}/{file_info.path.stem}'
build_result = env.C(build_target, str(file_info.path))
env.Alias(str(file_info.chapter), build_result)
8 changes: 4 additions & 4 deletions sconscripts/cpp_SConscript
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Import('files_to_compile env')
from pathlib import Path

for file in files_to_compile:
chapter_name = file.parent.parent.parent.stem
env.CPlusPlus(f'#/build/cpp/{chapter_name}', str(file))
for file_info in files_to_compile:
build_target = f'#/build/{file_info.language}/{file_info.chapter}/{file_info.path.stem}'
build_result = env.CPlusPlus(build_target, str(file_info.path))
env.Alias(str(file_info.chapter), build_result)
8 changes: 4 additions & 4 deletions sconscripts/fortran_SConscript
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Import('files_to_compile env')
from pathlib import Path

for file in files_to_compile:
chapter_name = file.parent.parent.parent.stem
env.Fortran(f'#/build/fortran/{chapter_name}', str(file))
for file_info in files_to_compile:
build_target = f'#/build/{file_info.language}/{file_info.chapter}/{file_info.path.stem}'
build_result = env.Fortran(build_target, str(file_info.path))
env.Alias(str(file_info.chapter), build_result)
8 changes: 4 additions & 4 deletions sconscripts/go_SConscript
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Import('files_to_compile env')
from pathlib import Path

for file in files_to_compile:
chapter_name = file.parent.parent.parent.stem
env.Go(f'#/build/go/{chapter_name}', str(file))
for file_info in files_to_compile:
build_target = f'#/build/{file_info.language}/{file_info.chapter}/{file_info.path.stem}'
build_result = env.Go(build_target, str(file_info.path))
env.Alias(str(file_info.chapter), build_result)
23 changes: 12 additions & 11 deletions sconscripts/rust_SConscript
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
Import('files_to_compile env')
from pathlib import Path

for file in files_to_compile:
chapter_name = file.parent.parent.parent.stem
if (file.parent / 'Cargo.toml').exists():
env.cargo(target=f'#/build/rust/{chapter_name}',
source=str(file),
MANIFEST=str(file.parent / 'Cargo.toml'),
SOURCE_DIR=str(file.parent))
env.Clean('rust', str(file.parent / 'target'))
for file_info in files_to_compile:
build_target = f'#/build/{file_info.language}/{file_info.chapter}/{file_info.path.stem}'
if (file_info.path.parent / 'Cargo.toml').exists():
build_result = env.cargo(target=build_target,
source=str(file_info.path),
MANIFEST=str(file_info.path.parent / 'Cargo.toml'),
SOURCE_DIR=str(file_info.path.parent))
env.Clean('rust', str(file_info.path.parent / 'target'))
else:
env.rustc(f'#/build/rust/{chapter_name}', str(file))
env.Clean('rust', f'#/build/rust/{chapter_name}.pdb')
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)