Skip to content

Commit

Permalink
Add sample build extension (#41)
Browse files Browse the repository at this point in the history
Add new sample build extenison.
Fix bugs in Soup CLI where it is not properly installing dev dependencies.
Switch back from "Extensions" to "DevDependencies".
Update and publish new versions of the Build core and extensions packages.
  • Loading branch information
mwasplund authored May 20, 2020
1 parent 70a478f commit 826a86c
Show file tree
Hide file tree
Showing 33 changed files with 590 additions and 58 deletions.
2 changes: 1 addition & 1 deletion Docs/Proposal.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ The preprocessor is, until now, a point of failure that could not be protected a
Another major issue with sharing code between different projects is incompatible language standards. In general it is straightforward to pull source that targets an earlier versions of the language into a project with a newer version (unless the old code uses a removed standard library feature). Header only libraries can have preprocessor conditionals for different language versions and using a C layer can help alleviate this issue. However, this may be another instance where C++ Modules can utilize the Binary Interface layer to allow for inter-module libraries to maintain a compatible layer and still allow for different language versions to be used internally. (Epochs anyone?!)

## Proposal
It is not enough to say that Modules will solve all of our problems. We will also have to define clear priorities for a collaboration first build system. The remainder of this document outlines the core Requirements and Goals for the proposed build system and gives a brief overview of the core design.
It is not enough to say that Modules will solve all of our problems. We will also have to define clear set of priorities for a collaboration first build system. The remainder of this document outlines the core Requirements and Goals for the proposed build system and gives a brief overview of the core design.

### Requirements
The set of requirements cannot be compromised. They do not necessarily have a priority order since they cannot conflict with each other, if the concepts are incompatible then the final system would be deemed a failure.
Expand Down
3 changes: 3 additions & 0 deletions Docs/Samples.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ This is a console application that has a single static library dependency.

## [Parse Json File](Samples/ParseJsonFile.md)
This is a console application that reads in a json file using the an external module and prints a single known property value.

## [Simple Build Extensio](Samples/SimpleBuildExtension.md)
This is a console application that uses a custom build extension to set a preprocessor definition to show how a user can easily author their own custom build logic that can be shared with others.
265 changes: 265 additions & 0 deletions Docs/Samples/SimpleBuildExtension.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
# Simple Build Extension
This is a console application that has a custom build extension that alters the build state.

[Source](https://github.com/mwasplund/Soup/tree/master/Samples/SimpleBuildExtension)

## Extension/Recipe.toml
The Recipe file that defines the build extension dynamic library "SimpleBuildExtension" that will register two new build tasks.
```
Name = "SimpleBuildExtension"
Type = "DynamicLibrary"
Version = "1.0.0"
Dependencies = [
"[email protected]",
"[email protected]",
"[email protected]",
]
Source = [
"Register.cpp"
]
```

## Extension/AfterBuildTask.h
A header file defining a custom build Task that will run after the build definition and simply log a message to the console.
```
#pragma once
namespace SimpleBuildExtension
{
/// <summary>
/// The simple build task that will run after the main build task
/// </summary>
class AfterBuildTask : public Opal::Memory::ReferenceCounted<Soup::Build::IBuildTask>
{
public:
/// <summary>
/// Get the task name
/// </summary>
const char* GetName() const noexcept override final
{
return "AfterBuild";
}
/// <summary>
/// Get the run before list
/// </summary>
Soup::Build::IList<const char*>& GetRunBeforeList() noexcept override final
{
return _runBeforeList;
}
/// <summary>
/// Get the run after list
/// </summary>
Soup::Build::IList<const char*>& GetRunAfterList() noexcept override final
{
return _runAfterList;
}
/// <summary>
/// The Core Execute task
/// </summary>
Soup::Build::OperationResult Execute(
Soup::Build::IBuildState& buildState) noexcept override final
{
auto buildStateWrapper = Soup::Build::Extensions::BuildStateWrapper(buildState);
try
{
// We cannot throw accross the DLL boundary for a build extension
// So all internal errors must be converted to error codes
Execute(buildStateWrapper);
return 0;
}
catch(...)
{
buildStateWrapper.LogError("Unknown Error!");
return -1;
}
}
private:
/// <summary>
/// The Core Execute task
/// </summary>
void Execute(Soup::Build::Extensions::BuildStateWrapper& buildState)
{
buildState.LogHighPriority("Running After Build!");
}
private:
static Soup::Build::Extensions::StringList _runBeforeList;
static Soup::Build::Extensions::StringList _runAfterList;
};
Soup::Build::Extensions::StringList AfterBuildTask::_runBeforeList =
Soup::Build::Extensions::StringList();
Soup::Build::Extensions::StringList AfterBuildTask::_runAfterList =
Soup::Build::Extensions::StringList({
"Build",
});
}
```

## Extension/BeforeBuildTask.h
A header file defining a custom build Task that will run before the build definition and sets a custom preprocessor definition to show how a user can alter the build state through an extension.
```
#pragma once
namespace SimpleBuildExtension
{
/// <summary>
/// The simple build task that will run before the main build task
/// </summary>
class BeforeBuildTask : public Opal::Memory::ReferenceCounted<Soup::Build::IBuildTask>
{
public:
/// <summary>
/// Get the task name
/// </summary>
const char* GetName() const noexcept override final
{
return "BeforeBuild";
}
/// <summary>
/// Get the run before list
/// </summary>
Soup::Build::IList<const char*>& GetRunBeforeList() noexcept override final
{
return _runBeforeList;
}
/// <summary>
/// Get the run after list
/// </summary>
Soup::Build::IList<const char*>& GetRunAfterList() noexcept override final
{
return _runAfterList;
}
/// <summary>
/// The Core Execute task
/// </summary>
Soup::Build::OperationResult Execute(
Soup::Build::IBuildState& buildState) noexcept override final
{
auto buildStateWrapper = Soup::Build::Extensions::BuildStateWrapper(buildState);
try
{
// We cannot throw accross the DLL boundary for a build extension
// So all internal errors must be converted to error codes
Execute(buildStateWrapper);
return 0;
}
catch(...)
{
buildStateWrapper.LogError("Unknown Error!");
return -1;
}
}
private:
/// <summary>
/// The Core Execute task
/// </summary>
void Execute(Soup::Build::Extensions::BuildStateWrapper& buildState)
{
buildState.LogHighPriority("Running Before Build!");
auto rootTable = buildState.GetActiveState();
auto buildTable = rootTable.EnsureValue("Build").EnsureTable();
// As a sample of what a build extension can do we set a new
// preprocessor definition to influence the build
auto preprocessorDefinitions = std::vector<std::string>({
"SPECIAL_BUILD",
});
buildTable.EnsureValue("PreprocessorDefinitions").EnsureList().Append(preprocessorDefinitions);
}
private:
static Soup::Build::Extensions::StringList _runBeforeList;
static Soup::Build::Extensions::StringList _runAfterList;
};
Soup::Build::Extensions::StringList BeforeBuildTask::_runBeforeList =
Soup::Build::Extensions::StringList({
"Build",
});
Soup::Build::Extensions::StringList BeforeBuildTask::_runAfterList =
Soup::Build::Extensions::StringList();
}
```

## Extension/Register.cpp
The Cpp file that implements the predefined `RegisterBuildExtension` C method to integrate our build Tasks into the build Engine.
```
#include <string_view>
import Opal;
import Soup.Build;
import Soup.Build.Extensions;
#include "AfterBuildTask.h"
#include "BeforeBuildTask.h"
#define DllExport __declspec( dllexport )
extern "C"
{
DllExport int RegisterBuildExtension(Soup::Build::IBuildSystem& buildSystem)
{
// Register the before build task
auto beforeBuildtask = Opal::Memory::Reference<SimpleBuildExtension::BeforeBuildTask>(
new SimpleBuildExtension::BeforeBuildTask());
buildSystem.RegisterTask(beforeBuildtask.GetRaw());
// Register the after build task
auto afterBuildtask = Opal::Memory::Reference<SimpleBuildExtension::AfterBuildTask>(
new SimpleBuildExtension::AfterBuildTask());
buildSystem.RegisterTask(afterBuildtask.GetRaw());
return 0;
}
}
```

## Executable/Recipe.toml
The Recipe file that defines the executable "SimpleBuildExtension.Executable". The one interesting part is the relative path reference to the custom build extension through "DevDependnecies".
```
Name = "SimpleBuildExtension.Executable"
Type = "Executable"
Version = "1.0.0"
DevDependencies = [
"../Extension"
]
Source = [
"Main.cpp"
]
```

## MyApplication/Main.cpp
A simple main method that prints our "Hello World, Soup Style!" only if the build extension was able to set the custom preprocessor definition "SPECIAL_BUILD".
```
#include <iostream>
int main()
{
#ifdef SPECIAL_BUILD
std::cout << "Hello World, Soup Style!" << std::endl;
#else
std::cout << "Hello World..." << std::endl;
#endif
return 0;
}
```

## .gitignore
A simple git ignore file to exclude all Soup build output.
```
out/
```
1 change: 1 addition & 0 deletions Samples/SimpleBuildExtension/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
out/
12 changes: 12 additions & 0 deletions Samples/SimpleBuildExtension/Executable/Main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include <iostream>

int main()
{
#ifdef SPECIAL_BUILD
std::cout << "Hello World, Soup Style!" << std::endl;
#else
std::cout << "Hello World..." << std::endl;
#endif

return 0;
}
9 changes: 9 additions & 0 deletions Samples/SimpleBuildExtension/Executable/Recipe.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Name = "SimpleBuildExtension.Executable"
Type = "Executable"
Version = "1.0.0"
DevDependencies = [
"../Extension"
]
Source = [
"Main.cpp"
]
77 changes: 77 additions & 0 deletions Samples/SimpleBuildExtension/Extension/AfterBuildTask.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#pragma once

namespace SimpleBuildExtension
{
/// <summary>
/// The simple build task that will run after the main build task
/// </summary>
class AfterBuildTask : public Opal::Memory::ReferenceCounted<Soup::Build::IBuildTask>
{
public:
/// <summary>
/// Get the task name
/// </summary>
const char* GetName() const noexcept override final
{
return "AfterBuild";
}

/// <summary>
/// Get the run before list
/// </summary>
Soup::Build::IList<const char*>& GetRunBeforeList() noexcept override final
{
return _runBeforeList;
}

/// <summary>
/// Get the run after list
/// </summary>
Soup::Build::IList<const char*>& GetRunAfterList() noexcept override final
{
return _runAfterList;
}

/// <summary>
/// The Core Execute task
/// </summary>
Soup::Build::OperationResult Execute(
Soup::Build::IBuildState& buildState) noexcept override final
{
auto buildStateWrapper = Soup::Build::Extensions::BuildStateWrapper(buildState);

try
{
// We cannot throw accross the DLL boundary for a build extension
// So all internal errors must be converted to error codes
Execute(buildStateWrapper);
return 0;
}
catch(...)
{
buildStateWrapper.LogError("Unknown Error!");
return -1;
}
}

private:
/// <summary>
/// The Core Execute task
/// </summary>
void Execute(Soup::Build::Extensions::BuildStateWrapper& buildState)
{
buildState.LogHighPriority("Running After Build!");
}

private:
static Soup::Build::Extensions::StringList _runBeforeList;
static Soup::Build::Extensions::StringList _runAfterList;
};

Soup::Build::Extensions::StringList AfterBuildTask::_runBeforeList =
Soup::Build::Extensions::StringList();
Soup::Build::Extensions::StringList AfterBuildTask::_runAfterList =
Soup::Build::Extensions::StringList({
"Build",
});
}
Loading

0 comments on commit 826a86c

Please sign in to comment.