Skip to content

Commit

Permalink
CMakeGenerator done
Browse files Browse the repository at this point in the history
  • Loading branch information
cvicentiu committed Jan 1, 2025
1 parent 58b5d75 commit 8240c9f
Show file tree
Hide file tree
Showing 8 changed files with 259 additions and 125 deletions.
27 changes: 0 additions & 27 deletions steps/cmake/cmake_options.py

This file was deleted.

2 changes: 2 additions & 0 deletions steps/cmake/compilers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
class CompilerCommand:
def __init__(self, cc: str, cxx: str):
assert isinstance(cc, str)
assert isinstance(cxx, str)
self.cc_ = cc
self.cxx_ = cxx

Expand Down
16 changes: 0 additions & 16 deletions steps/cmake/flags.py

This file was deleted.

79 changes: 60 additions & 19 deletions steps/cmake/generator.py
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
61 changes: 0 additions & 61 deletions steps/cmake/mariadb_options.py

This file was deleted.

105 changes: 105 additions & 0 deletions steps/cmake/options.py
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})'
3 changes: 1 addition & 2 deletions steps/configure.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
from buildbot import interfaces, steps

from .base import BuildStep
from .cmake.cmake_options import CMakeOption, CMAKE
from .cmake.cmake_options import CMakeOption, BuildType, CMAKE
from .cmake.compilers import CompilerCommand
from .cmake.generator import CMakeGenerator
from .cmake.mariadb_options import BuildType


class ConfigureMariaDBCMakeStep(BuildStep):
Expand Down
Loading

0 comments on commit 8240c9f

Please sign in to comment.