Migrate code to use pathlib
This commit is contained in:
parent
06981cd027
commit
63574f95cf
2 changed files with 55 additions and 52 deletions
14
make.py
14
make.py
|
|
@ -1,7 +1,7 @@
|
||||||
#! python3
|
#! python3
|
||||||
|
|
||||||
import glob
|
|
||||||
import os
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from umake import make
|
from umake import make
|
||||||
|
|
||||||
|
|
@ -12,10 +12,10 @@ class Config:
|
||||||
IGNORE_APPS = []
|
IGNORE_APPS = []
|
||||||
JOB_COUNT = int(os.cpu_count() * 0.8) # Concurent jobs (multi-processing)
|
JOB_COUNT = int(os.cpu_count() * 0.8) # Concurent jobs (multi-processing)
|
||||||
|
|
||||||
BIN_DIR = 'bin' # Output directory (binaries)
|
BIN_DIR = Path('bin') # Output directory (binaries)
|
||||||
INCLUDE_DIR = 'include' # Include directory (header files)
|
INCLUDE_DIR = Path('include') # Include directory (header files)
|
||||||
OBJECT_DIR = 'obj' # Temporary directory (object files)
|
OBJECT_DIR = Path('obj') # Temporary directory (object files)
|
||||||
SOURCE_DIR = 'src' # Source directories
|
SOURCE_DIR = Path('src') # Source directories
|
||||||
|
|
||||||
COMMON_FLAGS = '-std=c++17' # Flags used for comiling and linking
|
COMMON_FLAGS = '-std=c++17' # Flags used for comiling and linking
|
||||||
COMMON_DEBUG_FLAGS = '-g' # Flags added in debug mode
|
COMMON_DEBUG_FLAGS = '-g' # Flags added in debug mode
|
||||||
|
|
@ -23,8 +23,8 @@ class Config:
|
||||||
COMPILE_FLAGS = f'-Wall -I{INCLUDE_DIR}' # Flags added for compiling (recommandation : `pkg-config --cflags`)
|
COMPILE_FLAGS = f'-Wall -I{INCLUDE_DIR}' # Flags added for compiling (recommandation : `pkg-config --cflags`)
|
||||||
LINK_FLAGS = '' # Flags added for linking (recommandation : `pkg-config --libs`)
|
LINK_FLAGS = '' # Flags added for linking (recommandation : `pkg-config --libs`)
|
||||||
|
|
||||||
CPP_HEADERS = glob.glob(os.path.join(INCLUDE_DIR, '**', '*.hpp'), recursive=True)
|
CPP_HEADERS = INCLUDE_DIR.rglob('*.hpp')
|
||||||
CPP_SOURCES = glob.glob(os.path.join(SOURCE_DIR, '**', '*.cpp'), recursive=True)
|
CPP_SOURCES = SOURCE_DIR.rglob('*.cpp')
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
|
||||||
93
umake.py
93
umake.py
|
|
@ -12,27 +12,26 @@ from typing import List
|
||||||
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
CC = 'g++'
|
CC = 'g++' # Compiler to call
|
||||||
APPS = ['app_name']
|
APPS = ['app_name'] # Output binaries (need to be found as .cpp directly in SOURCE_DIR)
|
||||||
IGNORE_APPS = []
|
JOB_COUNT = int(os.cpu_count() * 0.8) # Concurent jobs (multi-processing)
|
||||||
JOB_COUNT = 1
|
|
||||||
|
|
||||||
BIN_DIR = 'bin'
|
BIN_DIR = Path('bin') # Output directory (binaries)
|
||||||
INCLUDE_DIR = 'include'
|
INCLUDE_DIR = Path('include') # Include directory (header files)
|
||||||
OBJECT_DIR = 'obj'
|
OBJECT_DIR = Path('obj') # Temporary directory (object files)
|
||||||
SOURCE_DIR = 'src'
|
SOURCE_DIR = Path('src') # Source directories
|
||||||
|
|
||||||
COMMON_FLAGS = '-std=c++17'
|
COMMON_FLAGS = '-std=c++17' # Flags used for comiling and linking
|
||||||
COMMON_DEBUG_FLAGS = '-g'
|
COMMON_DEBUG_FLAGS = '-g' # Flags added in debug mode
|
||||||
COMMON_RELEASE_FLAGS = '-O2 -flto'
|
COMMON_RELEASE_FLAGS = '-O2 -flto' # Flags added in release mode
|
||||||
COMPILE_FLAGS = f'-Wall -I{INCLUDE_DIR}'
|
COMPILE_FLAGS = f'-Wall -I{INCLUDE_DIR}' # Flags added for compiling (recommandation : `pkg-config --cflags`)
|
||||||
LINK_FLAGS = ''
|
LINK_FLAGS = '' # Flags added for linking (recommandation : `pkg-config --libs`)
|
||||||
|
|
||||||
CPP_HEADERS = []
|
CPP_HEADERS = INCLUDE_DIR.rglob('*.hpp')
|
||||||
CPP_SOURCES = []
|
CPP_SOURCES = SOURCE_DIR.rglob('*.cpp')
|
||||||
|
|
||||||
|
|
||||||
def get_hash(path: str) -> str:
|
def get_hash(path: Path) -> str:
|
||||||
with open(path, 'r') as hashing_file:
|
with open(path, 'r') as hashing_file:
|
||||||
hash_obj = hashlib.md5()
|
hash_obj = hashlib.md5()
|
||||||
hash_obj.update(hashing_file.read().encode())
|
hash_obj.update(hashing_file.read().encode())
|
||||||
|
|
@ -55,19 +54,20 @@ def make(config: Config):
|
||||||
# Update flags and directories for mode debug/release
|
# Update flags and directories for mode debug/release
|
||||||
if arguments.type == 'debug':
|
if arguments.type == 'debug':
|
||||||
config.COMMON_FLAGS += ' ' + config.COMMON_DEBUG_FLAGS
|
config.COMMON_FLAGS += ' ' + config.COMMON_DEBUG_FLAGS
|
||||||
config.OBJECT_DIR = os.path.join(config.OBJECT_DIR, 'debug')
|
config.OBJECT_DIR = config.OBJECT_DIR / 'debug'
|
||||||
else:
|
else:
|
||||||
config.COMMON_FLAGS += ' ' + config.COMMON_RELEASE_FLAGS
|
config.COMMON_FLAGS += ' ' + config.COMMON_RELEASE_FLAGS
|
||||||
config.OBJECT_DIR = os.path.join(config.OBJECT_DIR, 'release')
|
config.OBJECT_DIR = config.OBJECT_DIR / 'release'
|
||||||
|
|
||||||
# Create list of source to process (tuple[source_path, object_path])
|
# Create list of source to process (tuple[source_path, object_path])
|
||||||
compile_list = [(source_file, source_file[:-4].replace(config.SOURCE_DIR, config.OBJECT_DIR) + '.o')
|
compile_list = [(Path(source_file),
|
||||||
|
config.OBJECT_DIR / source_file.parent.relative_to(config.SOURCE_DIR) / (source_file.stem + '.o'))
|
||||||
for source_file in config.CPP_SOURCES]
|
for source_file in config.CPP_SOURCES]
|
||||||
todo_list = []
|
todo_list = []
|
||||||
|
|
||||||
hash_dict = {}
|
hash_dict = {}
|
||||||
if os.path.exists(os.path.join(config.OBJECT_DIR, 'hash.json')):
|
if (config.OBJECT_DIR / 'hash.json').exists():
|
||||||
with open(os.path.join(config.OBJECT_DIR, 'hash.json'), 'r') as hash_file:
|
with open(config.OBJECT_DIR / 'hash.json', 'r') as hash_file:
|
||||||
hash_dict = json.loads(hash_file.read())
|
hash_dict = json.loads(hash_file.read())
|
||||||
|
|
||||||
# Check header files (if any modification is done all source file will be processed to avoid any problem)
|
# Check header files (if any modification is done all source file will be processed to avoid any problem)
|
||||||
|
|
@ -75,18 +75,19 @@ def make(config: Config):
|
||||||
header_hash_dict = {}
|
header_hash_dict = {}
|
||||||
for header_path in config.CPP_HEADERS:
|
for header_path in config.CPP_HEADERS:
|
||||||
header_hash = get_hash(header_path)
|
header_hash = get_hash(header_path)
|
||||||
if header_path not in hash_dict or hash_dict[header_path] != header_hash:
|
if str(header_path) not in hash_dict or hash_dict[str(header_path)] != header_hash:
|
||||||
header_hash_dict[header_path] = header_hash
|
header_hash_dict[str(header_path)] = header_hash
|
||||||
header_changed = True
|
header_changed = True
|
||||||
|
|
||||||
# Check source file and generate compilation commands to execute
|
# Check source file and generate compilation commands to execute
|
||||||
for source_path, object_path in compile_list:
|
for source_path, object_path in compile_list:
|
||||||
cmd = ' '.join([config.CC, config.COMMON_FLAGS, config.COMPILE_FLAGS, source_path, '-c', '-o', object_path])
|
cmd = ' '.join([config.CC, config.COMMON_FLAGS, config.COMPILE_FLAGS,
|
||||||
if not os.path.exists(os.path.dirname(object_path)):
|
str(source_path), '-c', '-o', str(object_path)])
|
||||||
os.makedirs(os.path.dirname(object_path))
|
if not object_path.parent.exists():
|
||||||
|
object_path.parent.mkdir(parents=True)
|
||||||
source_hash = get_hash(source_path)
|
source_hash = get_hash(source_path)
|
||||||
if (header_changed or not os.path.exists(object_path)
|
if (header_changed or not object_path.exists()
|
||||||
or source_path not in hash_dict or hash_dict[source_path] != source_hash):
|
or str(source_path) not in hash_dict or hash_dict[str(source_path)] != source_hash):
|
||||||
todo_list.append((source_path, source_hash, cmd))
|
todo_list.append((source_path, source_hash, cmd))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
@ -105,14 +106,14 @@ def make(config: Config):
|
||||||
if oldest_job.returncode != 0:
|
if oldest_job.returncode != 0:
|
||||||
error_path = job_path
|
error_path = job_path
|
||||||
break
|
break
|
||||||
hash_dict[job_path] = job_hash # Update hash if no error
|
hash_dict[str(job_path)] = job_hash # Update hash if no error
|
||||||
if error_path is None:
|
if error_path is None:
|
||||||
for job_path, job_hash, job in jobs: # Wait the last jobs to finish
|
for job_path, job_hash, job in jobs: # Wait the last jobs to finish
|
||||||
job.wait()
|
job.wait()
|
||||||
if job.returncode != 0:
|
if job.returncode != 0:
|
||||||
error_path = job_path
|
error_path = job_path
|
||||||
break
|
break
|
||||||
hash_dict[job_path] = job_hash # Update hash if no error
|
hash_dict[str(job_path)] = job_hash # Update hash if no error
|
||||||
else: # Single-process
|
else: # Single-process
|
||||||
for source_path, source_hash, cmd in todo_list:
|
for source_path, source_hash, cmd in todo_list:
|
||||||
print(cmd)
|
print(cmd)
|
||||||
|
|
@ -120,29 +121,31 @@ def make(config: Config):
|
||||||
if complete.returncode != 0:
|
if complete.returncode != 0:
|
||||||
error_path = source_path
|
error_path = source_path
|
||||||
break
|
break
|
||||||
hash_dict[source_path] = source_hash # Update hash if no error
|
hash_dict[str(source_path)] = source_hash # Update hash if no error
|
||||||
if error_path:
|
if error_path:
|
||||||
print(f'Error compiling {error_path}')
|
print(f'Error compiling {error_path}')
|
||||||
with open(os.path.join(config.OBJECT_DIR, 'hash.json'), 'w') as hash_file:
|
with open(config.OBJECT_DIR / 'hash.json', 'w') as hash_file:
|
||||||
hash_file.write(json.dumps(hash_dict, indent=1))
|
hash_file.write(json.dumps(hash_dict, indent=1))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Running linking processes
|
# Running linking processes
|
||||||
if not os.path.exists(config.BIN_DIR):
|
if not config.BIN_DIR.exists():
|
||||||
os.makedirs(config.BIN_DIR)
|
config.BIN_DIR.mkdir(parents=True)
|
||||||
for app_name in config.APPS:
|
all_app_objects = [config.OBJECT_DIR / Path(app_path).parent / (Path(app_path).stem + '.o')
|
||||||
if 'IGNORE_APPS' in config.__dict__ and app_name in config.IGNORE_APPS:
|
for app_path in config.APPS]
|
||||||
|
for app_path, app_object_path in zip(config.APPS, all_app_objects):
|
||||||
|
if 'IGNORE_APPS' in config.__dict__ and app_path in config.IGNORE_APPS:
|
||||||
continue
|
continue
|
||||||
app_path = Path(config.BIN_DIR, app_name)
|
bin_path = config.BIN_DIR / app_path
|
||||||
if not app_path.parent.exists():
|
if not bin_path.parent.exists():
|
||||||
app_path.parent.mkdir(parents=True)
|
bin_path.parent.mkdir(parents=True)
|
||||||
app_objects = [file_name + '.o' for file_name in config.APPS if file_name != app_name]
|
object_files = [str(object_path) for _, object_path in compile_list
|
||||||
object_files = [object_path for _, object_path in compile_list
|
if object_path not in all_app_objects]
|
||||||
if os.path.basename(object_path) not in app_objects]
|
object_files.append(str(app_object_path))
|
||||||
cmd = ' '.join([config.CC, config.COMMON_FLAGS, *object_files, '-o', str(app_path), config.LINK_FLAGS])
|
cmd = ' '.join([config.CC, config.COMMON_FLAGS, *object_files, '-o', str(bin_path), config.LINK_FLAGS])
|
||||||
complete = subprocess.run(cmd, check=False, shell=True)
|
complete = subprocess.run(cmd, check=False, shell=True)
|
||||||
if complete.returncode != 0:
|
if complete.returncode != 0:
|
||||||
error_path = app_name
|
error_path = app_path
|
||||||
if error_path:
|
if error_path:
|
||||||
with open(os.path.join(config.OBJECT_DIR, 'hash.json'), 'w') as hash_file:
|
with open(os.path.join(config.OBJECT_DIR, 'hash.json'), 'w') as hash_file:
|
||||||
hash_file.write(json.dumps(hash_dict, indent=1))
|
hash_file.write(json.dumps(hash_dict, indent=1))
|
||||||
|
|
@ -152,5 +155,5 @@ def make(config: Config):
|
||||||
# Updating header hashes only if everything compiled and linked correctly
|
# Updating header hashes only if everything compiled and linked correctly
|
||||||
for header_path in header_hash_dict:
|
for header_path in header_hash_dict:
|
||||||
hash_dict[header_path] = header_hash_dict[header_path]
|
hash_dict[header_path] = header_hash_dict[header_path]
|
||||||
with open(os.path.join(config.OBJECT_DIR, 'hash.json'), 'w') as hash_file:
|
with open(config.OBJECT_DIR / 'hash.json', 'w') as hash_file:
|
||||||
hash_file.write(json.dumps(hash_dict, indent=1))
|
hash_file.write(json.dumps(hash_dict, indent=1))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue