-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
259 additions
and
125 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,53 +1,94 @@ | ||
from typing import Iterable | ||
|
||
from .cmake_options import ( | ||
CMAKE, | ||
) | ||
from .compilers import CompilerCommand | ||
from .options import CMakeFlag, CMakeOption | ||
from .options import CMAKE, BuildConfig, CMakeOption | ||
|
||
|
||
class DuplicateFlagException(Exception): | ||
pass | ||
def __init__(self, flag_name: str, existing_value: str, new_value: str): | ||
super().__init__( | ||
f"Duplicate flag detected: {flag_name}" | ||
f"(existing: {existing_value}, new: {new_value})" | ||
) | ||
super().__init__(f"Duplicate flag detected: {flag_name}") | ||
|
||
|
||
class CMakeGenerator: | ||
# Default path is "in source build" | ||
def __init__(self, flags: Iterable[CMakeFlag], | ||
''' | ||
Generates a CMake command with specified flags. | ||
''' | ||
|
||
def __init__(self, flags: Iterable[CMakeOption], | ||
source_path: str = '.'): | ||
# Use a dictionary to only allow flags to specified once. | ||
self.flags: dict[str, CMakeFlag] = {} | ||
''' | ||
Initializes the CMakeGenerator with an optional list of flags. | ||
Args: | ||
flags: An iterable of CMakeFlag objects. | ||
source_path: The source path to the base CMakeLists.txt file. | ||
Default path is "in source build". | ||
''' | ||
self.flags: dict[str, CMakeOption] = {} | ||
self.source_path = source_path | ||
for flag in flags: | ||
self.flags[flag.name] = self.flags[flag] | ||
self.append_flags(flags) | ||
|
||
def set_compiler(self, compiler: CompilerCommand): | ||
''' | ||
Sets the compiler options for C and C++ compilers. | ||
Args: | ||
compiler: An instance of CompilerCommand. | ||
''' | ||
assert isinstance(compiler, CompilerCommand) | ||
self.append_flags([ | ||
CMakeOption(CMAKE.C_COMPILER, compiler.cc), | ||
CMakeOption(CMAKE.CXX_COMPILER, compiler.cc), | ||
CMakeOption(CMAKE.CXX_COMPILER, compiler.cxx), | ||
]) | ||
|
||
def use_ccache(self): | ||
''' | ||
Configures CMake to use ccache for faster builds. | ||
''' | ||
self.append_flags([ | ||
CMakeOption(CMAKE.C_COMPILER_LAUNCHER, 'ccache'), | ||
CMakeOption(CMAKE.CXX_COMPILER_LAUNCHER, 'ccache') | ||
CMakeOption(CMAKE.CXX_COMPILER_LAUNCHER, 'ccache'), | ||
]) | ||
|
||
def append_flags(self, flags: Iterable[CMakeFlag]): | ||
# TODO(cvicentiu) write unit test. | ||
def set_build_config(self, config: BuildConfig): | ||
''' | ||
Set the build config flag. This is separate because of it being a | ||
"one-off" special flag. | ||
''' | ||
self.append_flags([CMakeOption('BUILD_CONFIG', config)]) | ||
|
||
def append_flags(self, flags: Iterable[CMakeOption]): | ||
''' | ||
Appends new flags to the generator. | ||
Raises: | ||
DuplicateFlagException: If a flag with the same name already | ||
exists. | ||
''' | ||
for flag in flags: | ||
# Do not allow duplicate flags being set. | ||
# Flags should only be set once to avoid confusion about them | ||
# being overwritten. | ||
if flag.name in self.flags[flag.name]: | ||
raise DuplicateFlagException(flag.name) | ||
if flag.name in self.flags: | ||
existing_flag = self.flags[flag.name] | ||
raise DuplicateFlagException(flag.name, | ||
existing_flag.value, | ||
flag.value) | ||
self.flags[flag.name] = flag | ||
|
||
def generate(self) -> list[str]: | ||
''' | ||
Generates the CMake command as a list of strings. | ||
''' | ||
result = [ | ||
'cmake', | ||
self.source_path | ||
] | ||
for flag in sorted(list(self.flags.values), lambda x: x.name): | ||
result.append(f'-D{flag.name}={flag.value}') | ||
|
||
for flag in sorted(list(self.flags.values()), key=lambda x: x.name): | ||
result.append(flag.as_cmd_arg()) | ||
return result |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
from enum import StrEnum | ||
|
||
|
||
# Flag names use UPPER_CASE | ||
class CMAKE(StrEnum): | ||
''' | ||
Explicitly enumerates valid CMake flags to enforce type safety | ||
and avoid typos in flag names. | ||
''' | ||
AR = 'AR' | ||
BUILD_TYPE = 'BUILD_TYPE' | ||
CXX_COMPILER = 'CXX_COMPILER' | ||
CXX_FLAGS = 'CXX_FLAGS' | ||
C_COMPILER = 'C_COMPILER' | ||
C_FLAGS = 'C_FLAGS' | ||
C_COMPILER_LAUNCHER = 'C_COMPILER_LAUNCHER' | ||
CXX_COMPILER_LAUNCHER = 'CXX_COMPILER_LAUNCHER' | ||
INSTALL_PREFIX = 'INSTALL_PREFIX' | ||
LIBRARY_PATH = 'LIBRARY_PATH' | ||
|
||
def __str__(self): | ||
return f'CMAKE_{self.value}' | ||
|
||
|
||
class PLUGIN(StrEnum): | ||
""" | ||
Enumerates valid plugin options for MariaDB's CMake configuration. | ||
""" | ||
ARCHIVE_STORAGE_ENGINE = 'ARCHIVE' | ||
CONNECT_STORAGE_ENGINE = 'CONNECT' | ||
ROCKSDB_STORAGE_ENGINE = 'ROCKSDB' | ||
TOKUDB_STORAGE_ENGINE = 'TOKUDB' | ||
|
||
def __str__(self): | ||
return f'PLUGIN_{self.value}' | ||
|
||
|
||
class WITH(StrEnum): | ||
""" | ||
Enumerates valid options for MariaDB's WITH flags. | ||
""" | ||
ASAN = 'ASAN' | ||
DBUG_TRACE = 'DBUG_TRACE' | ||
EMBEDDED_SERVER = 'EMBEDDED_SERVER' | ||
JEMALLOC = 'JEMALLOC' | ||
SAFEMALLOC = 'SAFEMALLOC' | ||
UBSAN = 'UBSAN' | ||
UNIT_TESTS = 'UNIT_TESTS' | ||
VALGRIND = 'VALGRIND' | ||
|
||
def __str__(self): | ||
return f'WITH_{self.value}' | ||
|
||
|
||
# Flag values use CapitalCase | ||
class BuildType(StrEnum): | ||
""" | ||
Enumerates build types for CMake. | ||
""" | ||
RELEASE = 'Release' | ||
DEBUG = 'Debug' | ||
RELWITHDEBUG = 'RelWithDebInfo' | ||
|
||
|
||
class BuildConfig(StrEnum): | ||
""" | ||
Used for -DBUILD_CONFIG=<value> of cmake. | ||
Enumerates build configurations for MariaDB's CMake. | ||
""" | ||
MYSQL_RELEASE = 'mysql_release' | ||
|
||
|
||
class CMakeOption: | ||
''' | ||
Represents a CMake option in the form `-D<name>=<value>`. | ||
''' | ||
|
||
@staticmethod | ||
def _quote_value(value: str): | ||
''' | ||
Quote the value if it contains spaces or special characters. | ||
''' | ||
if ' ' in value or '"' in value: | ||
return f'"{value.replace('"', '\\\"')}"' | ||
return value | ||
|
||
def __init__(self, name: StrEnum, value: str | bool): | ||
assert isinstance(name, StrEnum) | ||
assert isinstance(value, str) or isinstance(value, bool) | ||
self.name = str(name) | ||
if isinstance(value, bool): | ||
self.value = 'ON' if value else 'OFF' | ||
elif isinstance(value, str): | ||
self.value = value | ||
# Quote if necessary. | ||
self.value = self._quote_value(self.value) | ||
|
||
def as_cmd_arg(self) -> str: | ||
return f"-D{self.name}={self.value}" | ||
|
||
def __str__(self) -> str: | ||
return self.as_cmd_arg() | ||
|
||
def __repr__(self) -> str: | ||
return f'CMakeOption({self.name}, {self.value})' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.