Skip to content

Commit

Permalink
Build: Simplify usage of relative paths in includes and defines
Browse files Browse the repository at this point in the history
All paths everywhere are now relative to project root, but expressed relative to project location $(PROJECT_DIR).
Also defines like SC_LIBRARY_PATH are now just referencing $(PROJECT_ROOT), that expands to a path relative to location of project file $(PROJECT_DIR).

The location of _Outputs / _Intermediates / _Projects directories is coordinated in a single place by the build SC::Tool.
The SC-build.cpp doesn't need to "know" project location to compute the relative paths for outputs and intermediates.
By default also these paths are relative to the _Outputs and _Intermediates directories, but they can still be customized.

Some reasonable defaults have been choosen too, so that the build script becomes easier to read for average usage.

All these changes make a much simpler and coherent SC-build.cpp file.
  • Loading branch information
Pagghiu committed May 5, 2024
1 parent 1d0271c commit df488cd
Show file tree
Hide file tree
Showing 15 changed files with 440 additions and 249 deletions.
16 changes: 16 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,22 @@
"$gcc"
],
},
{
"label": "Build Coverage",
"type": "shell",
"command": "${workspaceRoot}/SC.sh",
"args": [
"build",
"coverage",
"DebugCoverage"
],
"windows": {
"command": "${workspaceRoot}/SC.bat",
},
"problemMatcher": [
"$gcc"
],
},
{
"label": "Launch Documentation WebServer",
"type": "shell",
Expand Down
14 changes: 9 additions & 5 deletions Documentation/Pages/Tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,9 @@ Possible output (Posix):
~/Developer/Projects/SC > ./SC.sh TestScript.cpp myAction param1 param2
Starting TestScript
Test "myAction" started
librarySource = "/Users/stefano/Developer/Projects/SC"
toolSource = "/Users/stefano/Developer/Projects/SC/Tools"
outputs = "/Users/stefano/Developer/Projects/SC/_Build"
librarySource = "/Users/user/Developer/Projects/SC"
toolSource = "/Users/user/Developer/Projects/SC/Tools"
toolDestination = "/Users/user/Developer/Projects/SC/_Build"
Hey This is the output from My Tool!!!
myAction
param1
Expand Down Expand Up @@ -131,8 +131,10 @@ Starting SC-build
SC-build "configure" started
librarySource = "/Users/user/Developer/Projects/SC"
toolSource = "/Users/user/Developer/Projects/SC/Tools"
outputs = "/Users/user/Developer/Projects/SC/_Build"
toolDestination = "/Users/user/Developer/Projects/SC/_Build"
projects = "/Users/user/Developer/Projects/SC/_Build/_Projects"
outputs = "/Users/user/Developer/Projects/SC/_Build/_Outputs"
intermediates = "/Users/user/Developer/Projects/SC/_Build/_Intermediates"
SC-build "configure" finished (took 72 ms)
~/Developer/Projects/SC >
```
Expand All @@ -149,8 +151,10 @@ Starting SC-build
SC-build "compile" started
librarySource = "/Users/user/Developer/Projects/SC"
toolSource = "/Users/user/Developer/Projects/SC/Tools"
outputs = "/Users/user/Developer/Projects/SC/_Build"
toolDestination = "/Users/user/Developer/Projects/SC/_Build"
projects = "/Users/user/Developer/Projects/SC/_Build/_Projects"
outputs = "/Users/user/Developer/Projects/SC/_Build/_Outputs"
intermediates = "/Users/user/Developer/Projects/SC/_Build/_Intermediates"
/Applications/Xcode.app/Contents/Developer/usr/bin/make clean
Cleaning SCTest
Creating /Users/user/Developer/Projects/SC/_Build/_Projects/Make/../../_Intermediates/SCTest/macOS-arm64-make-clang-Debug
Expand Down
152 changes: 84 additions & 68 deletions Libraries/Build/Build.cpp

Large diffs are not rendered by default.

61 changes: 44 additions & 17 deletions Libraries/Build/Build.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,9 +248,10 @@ struct Configuration
/// @brief A pre-made preset with pre-configured set of options
enum class Preset
{
None, ///< Custom configuration
Debug, ///< Debug configuration
Release, ///< Release configuration
None, ///< Custom configuration
Debug, ///< Debug configuration
DebugCoverage, ///< Debug coverage configuration
Release, ///< Release configuration
};

/// @brief Visual Studio platform toolset
Expand All @@ -262,11 +263,12 @@ struct Configuration
VisualStudio visualStudio; ///< Customize VisualStudio platformToolset

/// @brief Convert Preset to StringView
static constexpr StringView PresetToString(Preset preset)
[[nodiscard]] static constexpr StringView PresetToString(Preset preset)
{
switch (preset)
{
case Configuration::Preset::Debug: return "Debug";
case Configuration::Preset::DebugCoverage: return "DebugCoverage";
case Configuration::Preset::Release: return "Release";
case Configuration::Preset::None: return "None";
}
Expand All @@ -279,23 +281,40 @@ struct Configuration
preset = newPreset;
switch (preset)
{
case Configuration::Preset::Debug: SC_TRY(compile.set<Compile::optimizationLevel>(Optimization::Debug)); break;
case Configuration::Preset::DebugCoverage:
SC_TRY(compile.set<Compile::enableCoverage>(true));
SC_TRY(compile.set<Compile::optimizationLevel>(Optimization::Debug));
SC_TRY(compile.addDefines({"DEBUG=1"}));
break;
case Configuration::Preset::Debug:
SC_TRY(compile.set<Compile::optimizationLevel>(Optimization::Debug));
SC_TRY(compile.addDefines({"DEBUG=1"}));
break;
case Configuration::Preset::Release:
SC_TRY(compile.set<Compile::optimizationLevel>(Optimization::Release));
SC_TRY(compile.addDefines({"NDEBUG=1"}));
break;
case Configuration::Preset::None: break;
}
return true;
}

String name; ///< Configuration name
CompileFlags compile; ///< Configuration compile flags
LinkFlags link; ///< Configuration link flags
String outputPath; ///< Path where build outputs should be created
String intermediatesPath; ///< Path where build intermediate files will be created
[[nodiscard]] static constexpr StringView getStandardBuildDirectory()
{
return "$(TARGET_OS)-$(TARGET_ARCHITECTURES)-$(BUILD_SYSTEM)-$(COMPILER)-$(CONFIGURATION)";
}

String name; ///< Configuration name
String outputPath; ///< Exe path. If relative, it's appended to _Outputs relative to $(PROJECT_DIR).
String intermediatesPath; ///< Obj path. If relative, it's appended to _Intermediates relative to $(PROJECT_DIR).

CompileFlags compile; ///< Configuration compile flags
LinkFlags link; ///< Configuration link flags

Preset preset = Preset::None; ///< Build preset applied to this configuration
Architecture::Type architecture = Architecture::Any; ///< Restrict this configuration to a specific architecture

Configuration();
};

/// @brief Type of target artifact to build (executable, library)
Expand Down Expand Up @@ -399,12 +418,22 @@ struct Workspace
[[nodiscard]] Result validate() const;
};

struct Directories
{
String projectsDirectory;
String intermediatesDirectory;
String outputsDirectory;
String libraryDirectory;
};

/// @brief Describes a specific set of platforms, architectures and build generators to generate projects for
struct Parameters
{
Array<Platform::Type, 5> platforms; ///< Platforms to generate
Array<Architecture::Type, 5> architectures; ///< Architectures to generate
Generator::Type generator; ///< Build system types to generate

Directories directories;
};

/// @brief Top level build description holding all Workspace objects
Expand All @@ -415,8 +444,8 @@ struct Definition
/// @brief Generates projects for all workspaces, with specified parameters at given root path.
/// @param projectName Name of the workspace file / directory to generate
/// @param parameters Set of parameters with the wanted platforms, architectures and generators to generate
/// @param rootPath The path where workspace will be generated
Result configure(StringView projectName, const Parameters& parameters, StringView rootPath) const;
/// @param directories Contains projects, outputs and intermediates paths
Result configure(StringView projectName, const Parameters& parameters, Directories directories) const;
};

/// @brief Caches file paths by pre-resolving directory filter search masks
Expand Down Expand Up @@ -451,8 +480,7 @@ struct Action
Print,
Coverage
};
using ConfigureFunction = Result (*)(Build::Definition& definition, Build::Parameters& parameters,
StringView rootDirectory);
using ConfigureFunction = Result (*)(Build::Definition& definition, Build::Parameters& parameters);

static Result execute(const Action& action, ConfigureFunction configure, StringView projectName);

Expand All @@ -461,9 +489,8 @@ struct Action
Generator::Type generator = Generator::Type::Make;
Architecture::Type architecture = Architecture::Any;

StringView targetDirectory;
StringView libraryDirectory;
StringView configuration;
Directories directories;
StringView configuration;

private:
struct Internal;
Expand Down
57 changes: 53 additions & 4 deletions Libraries/Build/Internal/BuildWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,31 @@ namespace SC
{
namespace Build
{
struct RelativeDirectories
{
StringNative<256> relativeProjectsToOutputs; // _Projects ->_Outputs
StringNative<256> relativeProjectsToIntermediates; // _Projects ->_Intermediate
StringNative<256> relativeProjectsToProjectRoot; // _Projects -> Project::setRootDirectory
StringNative<256> projectRootRelativeToProjects; // Project root (expressed relative to $(PROJECT_DIR)

Result computeRelativeDirectories(Directories directories, Path::Type outputType, const Project& project,
const StringView projectDirFormatString)
{
SC_TRY(Path::relativeFromTo(directories.projectsDirectory.view(), directories.outputsDirectory.view(),
relativeProjectsToOutputs, Path::AsNative, outputType));
SC_TRY(Path::relativeFromTo(directories.projectsDirectory.view(), directories.intermediatesDirectory.view(),
relativeProjectsToIntermediates, Path::AsNative, outputType));

SC_TRY(Path::relativeFromTo(directories.projectsDirectory.view(), project.rootDirectory.view(),
relativeProjectsToProjectRoot, Path::AsNative, outputType));
SC_TRY(StringBuilder(projectRootRelativeToProjects, StringBuilder::Clear)
.format(projectDirFormatString, relativeProjectsToProjectRoot));

return Result(true);
}
};
struct WriterInternal;
}
} // namespace Build
} // namespace SC

struct SC::Build::WriterInternal
Expand Down Expand Up @@ -51,8 +74,34 @@ struct SC::Build::WriterInternal
Vector<RenderItem> renderItems;
};

[[nodiscard]] static bool fillFiles(const DefinitionCompiler& definitionCompiler, StringView destinationDirectory,
const Project& project, Vector<RenderItem>& outputFiles)
[[nodiscard]] static bool appendPrefixIfRelativePosix(StringView relativeVariable, StringBuilder& builder,
StringView text, StringView prefix)
{
if (not text.startsWith(relativeVariable) and not Path::isAbsolute(text, Path::AsNative))
{
SC_TRY(builder.append(relativeVariable));
SC_TRY(builder.append(Path::Posix::SeparatorStringView()));
SC_TRY(builder.append(prefix));
SC_TRY(builder.append(Path::Posix::SeparatorStringView()));
}
return true;
}

[[nodiscard]] static bool appendPrefixIfRelativeMSVC(StringView relativeVariable, StringBuilder& builder,
StringView text, StringView prefix)
{
if (not text.startsWith(relativeVariable) and not Path::isAbsolute(text, Path::AsNative))
{
SC_TRY(builder.append(relativeVariable));
SC_TRY(builder.append(prefix));
SC_TRY(builder.append(Path::Windows::SeparatorStringView()));
}
return true;
}

[[nodiscard]] static bool getPathsRelativeTo(StringView referenceDirectory,
const DefinitionCompiler& definitionCompiler, const Project& project,
Vector<RenderItem>& outputFiles)
{
String renderedFile;
for (const auto& file : project.files)
Expand Down Expand Up @@ -88,7 +137,7 @@ struct SC::Build::WriterInternal
{
renderItem.type = RenderItem::DebugVisualizerFile;
}
SC_TRY(Path::relativeFromTo(destinationDirectory, it.view(), renderItem.path,
SC_TRY(Path::relativeFromTo(referenceDirectory, it.view(), renderItem.path,
Path::Type::AsNative, // input type
Path::Type::AsPosix)); // output type
SC_TRY(Path::relativeFromTo(project.rootDirectory.view(), it.view(), renderItem.referencePath,
Expand Down
51 changes: 36 additions & 15 deletions Libraries/Build/Internal/BuildWriterMakefile.inl
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,17 @@ struct SC::Build::ProjectWriter::WriterMakefile
{
const Definition& definition;
const DefinitionCompiler& definitionCompiler;
const Directories& directories;

WriterMakefile(const Definition& definition, const DefinitionCompiler& definitionCompiler)
: definition(definition), definitionCompiler(definitionCompiler)
WriterMakefile(const Definition& definition, const DefinitionCompiler& definitionCompiler,
const Directories& directories)
: definition(definition), definitionCompiler(definitionCompiler), directories(directories)
{}
using RenderItem = WriterInternal::RenderItem;
using RenderGroup = WriterInternal::RenderGroup;
using Renderer = WriterInternal::Renderer;

[[nodiscard]] Result writeMakefile(StringBuilder& builder, const StringView destinationDirectory,
const Workspace& workspace, Renderer& renderer)
[[nodiscard]] Result writeMakefile(StringBuilder& builder, const Workspace& workspace, Renderer& renderer)
{
SC_COMPILER_WARNING_PUSH_UNUSED_RESULT;
builder.append(R"delimiter(ifeq ($(VERBOSE), 1)
Expand Down Expand Up @@ -138,18 +139,21 @@ Makefile.$(CONFIG).touched: Makefile
-include Makefile.$(CONFIG).touched
endif
)delimiter");

RelativeDirectories relativeDirectories;
for (const Project& project : workspace.projects)
{
SC_TRY(WriterInternal::fillFiles(definitionCompiler, destinationDirectory, project, renderer.renderItems));
SC_TRY(writeProject(builder, project, renderer));
SC_TRY(relativeDirectories.computeRelativeDirectories(directories, Path::AsPosix, project, "$(CURDIR)/{}"));
SC_TRY(WriterInternal::getPathsRelativeTo(directories.projectsDirectory.view(), definitionCompiler, project,
renderer.renderItems));
SC_TRY(writeProject(builder, project, renderer, relativeDirectories));
}

SC_COMPILER_WARNING_POP;
return Result(true);
}

[[nodiscard]] Result writeProject(StringBuilder& builder, const Project& project, Renderer& renderer)
[[nodiscard]] Result writeProject(StringBuilder& builder, const Project& project, Renderer& renderer,
const RelativeDirectories& relativeDirectories)
{
SC_COMPILER_WARNING_PUSH_UNUSED_RESULT;
SmallString<255> makeTarget;
Expand Down Expand Up @@ -188,7 +192,7 @@ endif
for (auto& it : *projectArray)
{
SC_TRY(builder.append(" \"-D"));
SC_TRY(appendVariable(builder, it.view(), makeTarget.view()));
SC_TRY(appendVariable(builder, it.view(), makeTarget.view(), relativeDirectories));
SC_TRY(builder.append("\""));
}
}
Expand All @@ -198,14 +202,21 @@ endif
for (auto& it : *includesArray)
{
SC_TRY(builder.append(" \"-I"));
SC_TRY(appendVariable(builder, it.view(), makeTarget.view()));
if (Path::isAbsolute(it.view(), Path::AsPosix))
{
builder.append(it.view());
}
else
{
builder.append("$(CURDIR)/{}/{}", relativeDirectories.relativeProjectsToProjectRoot, it.view());
}
SC_TRY(builder.append("\""));
}
}

for (const Configuration& configuration : project.configurations)
{
SC_TRY(writeConfiguration(builder, configuration, makeTarget.view(), renderer))
SC_TRY(writeConfiguration(builder, configuration, relativeDirectories, makeTarget.view(), renderer))
}

builder.append(R"delimiter(
Expand Down Expand Up @@ -423,7 +434,8 @@ $({0}_INTERMEDIATE_DIR)/{1}.o: $(CURDIR)/{2} | $({0}_INTERMEDIATE_DIR)
}

[[nodiscard]] Result writeConfiguration(StringBuilder& builder, const Configuration& configuration,
StringView makeTarget, Renderer& renderer)
const RelativeDirectories& relativeDirectories, StringView makeTarget,
Renderer& renderer)
{
SC_COMPILER_WARNING_PUSH_UNUSED_RESULT;
SC_COMPILER_UNUSED(builder);
Expand All @@ -434,10 +446,15 @@ $({0}_INTERMEDIATE_DIR)/{1}.o: $(CURDIR)/{2} | $({0}_INTERMEDIATE_DIR)
builder.append("\n\nifeq ($(CONFIG),{0})", configName.view());

builder.append("\n{0}_INTERMEDIATE_DIR := ", makeTarget);
SC_TRY(appendVariable(builder, configuration.intermediatesPath.view(), makeTarget));
WriterInternal::appendPrefixIfRelativePosix("$(CURDIR)", builder, configuration.intermediatesPath.view(),
relativeDirectories.relativeProjectsToIntermediates.view());

SC_TRY(appendVariable(builder, configuration.intermediatesPath.view(), makeTarget, relativeDirectories));

builder.append("\n{0}_TARGET_DIR := ", makeTarget);
SC_TRY(appendVariable(builder, configuration.outputPath.view(), makeTarget));
WriterInternal::appendPrefixIfRelativePosix("$(CURDIR)", builder, configuration.outputPath.view(),
relativeDirectories.relativeProjectsToOutputs.view());
SC_TRY(appendVariable(builder, configuration.outputPath.view(), makeTarget, relativeDirectories));

// TODO: De-hardcode debug and release optimization levels
if (configuration.compile.hasValue<Compile::optimizationLevel>(Optimization::Debug))
Expand Down Expand Up @@ -504,10 +521,14 @@ $({0}_INTERMEDIATE_DIR)/{1}.o: $(CURDIR)/{2} | $({0}_INTERMEDIATE_DIR)
return Result(true);
}

[[nodiscard]] static bool appendVariable(StringBuilder& builder, StringView text, StringView makeTarget)
[[nodiscard]] static bool appendVariable(StringBuilder& builder, StringView text, StringView makeTarget,
const RelativeDirectories& relativeDirectories)
{
const StringView relativeRoot = relativeDirectories.projectRootRelativeToProjects.view();

const StringBuilder::ReplacePair replacements[] = {
{"$(PROJECT_DIR)", "$(CURDIR)"}, //
{"$(PROJECT_ROOT)", relativeRoot}, //
{"$(CONFIGURATION)", "$(CONFIG)"}, //
{"$(PROJECT_NAME)", makeTarget}, //
{"$(TARGET_OS)", "$(TARGET_OS)"}, //
Expand Down
Loading

0 comments on commit df488cd

Please sign in to comment.