Skip to content

Commit

Permalink
Add support for building + testing both C++ & C# with CMake.
Browse files Browse the repository at this point in the history
This commit adds the ability to build both codebases with CMake. This is
of course primarily aimed at portability for building with C++, but is
nonetheless quite convenient for working on both of them at the same
time.

C# compilation is disabled by default since it requires you to be using
the Visual Studio generator in order to work - however, you should be
able to invoke the resulting project files from MSBuild if you don't
have or want the full Visual Studio IDE.

The code of the applications has been altered to separate unit tests
out. They now do not run unless there is some explicit call to invoke
them. This ensures that when CTest runs, it is able to execute the
different kinds of test separately, preventing mixing of results in the
event of a failure.
  • Loading branch information
Olipro committed Oct 31, 2023
1 parent 3935581 commit 12cc39d
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 67 deletions.
125 changes: 125 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
cmake_minimum_required(VERSION 3.12)
project(Miniscript VERSION 1.6.2 LANGUAGES C CXX)

option(MINISCRIPT_BUILD_TESTING "Build unit test executable" OFF)
option(MINISCRIPT_BUILD_CSHARP "Build CSharp binaries" OFF)

if(MINISCRIPT_BUILD_CSHARP)
enable_language(CSharp)
set(CMAKE_CSharp_FLAGS "/langversion:7.3")
set(CMAKE_DOTNET_TARGET_FRAMEWORK "net45")
set(CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION "v4.5")
set(DOTNET_REFS "System;System.Core")
add_library(miniscript-cs SHARED
MiniScript-cs/Miniscript.cs
MiniScript-cs/MiniscriptErrors.cs
MiniScript-cs/MiniscriptInterpreter.cs
MiniScript-cs/MiniscriptIntrinsics.cs
MiniScript-cs/MiniscriptKeywords.cs
MiniScript-cs/MiniscriptLexer.cs
MiniScript-cs/MiniscriptParser.cs
MiniScript-cs/MiniscriptTAC.cs
MiniScript-cs/MiniscriptTypes.cs
MiniScript-cs/MiniscriptUnitTest.cs
)
set_target_properties(miniscript-cs PROPERTIES
VS_GLOBAL_ROOTNAMESPACE "Miniscript"
VS_DOTNET_REFERENCES "${DOTNET_REFS}"
)
endif()

set(MINISCRIPT_HEADERS
MiniScript-cpp/src/MiniScript/Dictionary.h
MiniScript-cpp/src/MiniScript/List.h
MiniScript-cpp/src/MiniScript/MiniscriptErrors.h
MiniScript-cpp/src/MiniScript/MiniscriptInterpreter.h
MiniScript-cpp/src/MiniScript/MiniscriptIntrinsics.h
MiniScript-cpp/src/MiniScript/MiniscriptKeywords.h
MiniScript-cpp/src/MiniScript/MiniscriptLexer.h
MiniScript-cpp/src/MiniScript/MiniscriptParser.h
MiniScript-cpp/src/MiniScript/MiniscriptTAC.h
MiniScript-cpp/src/MiniScript/MiniscriptTypes.h
MiniScript-cpp/src/MiniScript/QA.h
MiniScript-cpp/src/MiniScript/RefCountedStorage.h
MiniScript-cpp/src/MiniScript/SimpleString.h
MiniScript-cpp/src/MiniScript/SimpleVector.h
MiniScript-cpp/src/MiniScript/SplitJoin.h
MiniScript-cpp/src/MiniScript/UnicodeUtil.h
MiniScript-cpp/src/MiniScript/UnitTest.h
)

set(MINICMD_HEADERS
MiniScript-cpp/src/DateTimeUtils.h
MiniScript-cpp/src/OstreamSupport.h
MiniScript-cpp/src/ShellIntrinsics.h
MiniScript-cpp/src/editline/config.h
MiniScript-cpp/src/editline/editline.h
MiniScript-cpp/src/editline/editline_internal.h
MiniScript-cpp/src/editline/os9.h
MiniScript-cpp/src/editline/unix.h
MiniScript-cpp/src/whereami/whereami.h
)

add_library(miniscript-cpp
MiniScript-cpp/src/MiniScript/Dictionary.cpp
MiniScript-cpp/src/MiniScript/List.cpp
MiniScript-cpp/src/MiniScript/MiniscriptInterpreter.cpp
MiniScript-cpp/src/MiniScript/MiniscriptIntrinsics.cpp
MiniScript-cpp/src/MiniScript/MiniscriptKeywords.cpp
MiniScript-cpp/src/MiniScript/MiniscriptLexer.cpp
MiniScript-cpp/src/MiniScript/MiniscriptParser.cpp
MiniScript-cpp/src/MiniScript/MiniscriptTAC.cpp
MiniScript-cpp/src/MiniScript/MiniscriptTypes.cpp
MiniScript-cpp/src/MiniScript/QA.cpp
MiniScript-cpp/src/MiniScript/SimpleString.cpp
MiniScript-cpp/src/MiniScript/SimpleVector.cpp
MiniScript-cpp/src/MiniScript/SplitJoin.cpp
MiniScript-cpp/src/MiniScript/UnicodeUtil.cpp
MiniScript-cpp/src/MiniScript/UnitTest.cpp
${MINISCRIPT_HEADERS}
)

target_include_directories(miniscript-cpp PUBLIC src/MiniScript)

if(NOT WIN32)
set(EDITLINE_SRC
MiniScript-cpp/src/editline/complete.c
MiniScript-cpp/src/editline/editline.c
MiniScript-cpp/src/editline/sysos9.c
MiniScript-cpp/src/editline/sysunix.c
)
endif()

add_executable(minicmd
MiniScript-cpp/src/main.cpp
MiniScript-cpp/src/DateTimeUtils.cpp
MiniScript-cpp/src/OstreamSupport.cpp
MiniScript-cpp/src/ShellIntrinsics.cpp
MiniScript-cpp/src/whereami/whereami.c
${EDITLINE_SRC}
${MINICMD_HEADERS}
)
target_include_directories(minicmd PRIVATE src/editline)
target_link_libraries(minicmd PRIVATE miniscript-cpp)

if(MINISCRIPT_BUILD_TESTING)
enable_testing()
add_custom_target(TestSuite SOURCES TestSuite.txt)
add_executable(tests-cpp MiniScript-cpp/src/MiniScript/UnitTest.cpp)
target_compile_definitions(tests-cpp PRIVATE UNIT_TEST_MAIN)
target_link_libraries(tests-cpp PRIVATE miniscript-cpp)
add_test(NAME Miniscript.cpp.UnitTests COMMAND tests-cpp)
add_test(NAME Miniscript.cpp.Integration COMMAND minicmd --itest ${CMAKE_SOURCE_DIR}/TestSuite.txt)
set_tests_properties(Miniscript.cpp.UnitTests Miniscript.cpp.Integration PROPERTIES FAIL_REGULAR_EXPRESSION "FAIL|Error")
if(MINISCRIPT_BUILD_CSHARP)
add_executable(tests-cs MiniScript-cs/Program.cs)
target_link_libraries(tests-cs PRIVATE miniscript-cs)
set_target_properties(tests-cs PROPERTIES
VS_GLOBAL_ROOTNAMESPACE "Miniscript"
VS_DOTNET_REFERENCES "${DOTNET_REFS}"
)
add_test(NAME Miniscript.cs.UnitTests COMMAND tests-cs --test)
add_test(NAME Miniscript.cs.Integration COMMAND tests-cs --test --integration ${CMAKE_SOURCE_DIR}/TestSuite.txt)
set_tests_properties(Miniscript.cs.UnitTests Miniscript.cs.Integration PROPERTIES FAIL_REGULAR_EXPRESSION "FAIL|Error")
endif()
endif()
25 changes: 0 additions & 25 deletions MiniScript-cpp/Makefile

This file was deleted.

30 changes: 10 additions & 20 deletions MiniScript-cpp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,25 @@

This folder contains the source code of the C++ implementation of the [MiniScript scripting language](http://miniscript.org), including the command-line host program.

## Building for macOS
## Building

Open the Xcode project (MiniScript.xcodeproj). Build.
MiniScript is built with CMake. You can generate your desired flavour of build files as usual from either the CMake GUI or using `cmake` on the commandline. If you are unfamiliar with CMake and want to build right now, use the GUI. If you cannot use the GUI, make a directory somewhere and, while in that directory, run `cmake path/to/miniscript` followed by `cmake --build`

(Note that if you run within XCode, it will work, but every input keystroke in the console will be doubled, because the readline library doesn't quite work properly with Xcode's console. It works fine in a real Terminal window though.)
Miniscript itself will be output as a shared library for you to link to. You can even `include()` the CMakeLists.txt of this project inside your own for clean dependency management.

You can also follow the Linux procedure, if you prefer command-line tools.
If you are only interested in the C# edition of MiniScript, there is a project file provided in the respective directory.

## Building for Linux
### CMake Build Options

Prerequisites: You will need make, gcc, and g++ installed.
Options can be controlled in the usual way - either within the CMake GUI or by passing `-D<OPTION>=ON` from your terminal.

Then use `make` in the directory containing this README to build the miniscript executable. The executable, `miniscript` should appear in the same directory.
#### MINISCRIPT_BUILD_TESTING

Other make options you can use:
This option controls whether or not unit tests binaries are built and added to CTest. For an overview of the flags passed to the binaries to cause them to execute tests, take a look in the testing section at the bottom of the `CMakeLists.txt` - however, rather than doing this, you can simply run `ctest` after building. Most IDEs integrate with CMake/CTest and will detect the tests. If you generated a multi-configuration build (such as a VS project) you would need to run `ctest -C <Debug/Release>`

- `make install`: ensures the executable has the proper `x` bits set, then installs a symbolic link to it in /usr/local/bin. Note that if you move the executable (or the directory it's in) somewhere else on your file system, this symbolic link will no longer work. You can fix it manually, or by running `make install` again from the new location.
### MINISCRIPT_BUILD_CSHARP

- `make clean`: deletes all the object (.o) files from the directory. You shouldn't need this unless something goes wrong during the normal `make` process.

- `make uninstall`: deletes the executable and the symbolic link in /usr/local/bin.

## Building for Windows

Install the [Visual Studio Command-Line Tools](https://docs.microsoft.com/en-us/cpp/build/walkthrough-compiling-a-native-cpp-program-on-the-command-line?view=vs-2019), and then you can build by `cd`ing into the `src` directory, and using this command:

`cl /EHsc /wd4068 *.cpp MiniScript/*.cpp whereami/*.c /Feminiscript.exe`

The output will be called `miniscript.exe` and located in the same directory.
This option is only supported when outputting a Visual Studio project. Attempting to enable this in any other environment will likely result in a build error - consult the documentation for your version of CMake as support for other platforms may become possible in the future.

## About the lib folder

Expand Down
6 changes: 6 additions & 0 deletions MiniScript-cpp/src/MiniScript/UnitTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,9 @@ namespace MiniScript {

}

#ifdef UNIT_TEST_MAIN
int main(int, const char*[]) {
MiniScript::UnitTest::RunAllTests();
}
#endif

3 changes: 0 additions & 3 deletions MiniScript-cpp/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#include <fstream>
#include "MiniScript/SimpleString.h"
#include "MiniScript/UnicodeUtil.h"
#include "MiniScript/UnitTest.h"
#include "MiniScript/SimpleVector.h"
#include "MiniScript/List.h"
#include "MiniScript/Dictionary.h"
Expand Down Expand Up @@ -252,8 +251,6 @@ int main(int argc, const char * argv[]) {
std::cout << "total RefCountedStorage instances at start (from static keywords, etc.): " << RefCountedStorage::instanceCount << std::endl;
#endif

UnitTest::RunAllTests();

#if(DEBUG)
std::cout << "StringStorage instances left: " << StringStorage::instanceCount << std::endl;
std::cout << "total RefCountedStorage instances left (includes 2 Unicode case maps): " << RefCountedStorage::instanceCount << std::endl;
Expand Down
45 changes: 26 additions & 19 deletions MiniScript-cs/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,30 +126,37 @@ static void RunFile(string path, bool dumpTAC=false) {
}

public static void Main(string[] args) {

Miniscript.HostInfo.name = "Test harness";

Print("Miniscript test harness.\n");

Print("Running unit tests.\n");
UnitTest.Run();
if (args.Length > 0 && args[0] == "--test") {
Miniscript.HostInfo.name = "Test harness";

if (args.Length > 2 && args[1] == "--integration") {
var file = string.IsNullOrEmpty(args[2]) ? "../../../TestSuite.txt" : args[2];
Print("Running test suite.\n");
RunTestSuite(file);
return;
}

Print("Miniscript test harness.\n");

Print("Running test suite.\n");
RunTestSuite("../../../TestSuite.txt");
Print("Running unit tests.\n");
UnitTest.Run();

Print("\n");
Print("\n");

const string quickTestFilePath = "../../../QuickTest.ms";
const string quickTestFilePath = "../../../QuickTest.ms";

if (File.Exists(quickTestFilePath)) {
Print("Running quick test.\n");
var stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
RunFile(quickTestFilePath, true);
stopwatch.Stop();
Print($"Run time: {stopwatch.Elapsed.TotalSeconds} sec");
} else {
Print("Quick test not found, skipping...\n");
if (File.Exists(quickTestFilePath)) {
Print("Running quick test.\n");
var stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
RunFile(quickTestFilePath, true);
stopwatch.Stop();
Print($"Run time: {stopwatch.Elapsed.TotalSeconds} sec");
} else {
Print("Quick test not found, skipping...\n");
}
return;
}

if (args.Length > 0) {
Expand Down

0 comments on commit 12cc39d

Please sign in to comment.