diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2019-06-14 18:05:12 -0400 |
|---|---|---|
| committer | Tim Foley <tfoleyNV@users.noreply.github.com> | 2019-06-14 15:05:12 -0700 |
| commit | 1fe24d3a74a9cd51c4a025cd0e78642f3e29df79 (patch) | |
| tree | a52d2b1e05f0d22accbb70eb4bea69d7c67455a4 | |
| parent | 8c56d83506ef92b15b15bdb5969008dd69c8d2a6 (diff) | |
Runtime Shared Library compilation and testing (#985)
* Removed the need for VisualStudio specific CPPCompiler
Improved the version parsing for gcc/clang
Removed need for slang-unix-cpp-compiler-util.cpp/.h
Remove binary before compiling in the compile c tests
* Moved VisualStudio calcArgs into CPPCompilerUtil - as code is not windows specific.
* Set up compile time version for gcc and clang
* Fix compilation on OSX - use remove instead of unlink for file deletion.
* On OSX - clang uses different string format.
* Removed /bin/sh invoking as not required for OSX.
* First pass working testing with shared libraries.
| -rw-r--r-- | source/core/slang-cpp-compiler.cpp | 48 | ||||
| -rw-r--r-- | source/core/slang-cpp-compiler.h | 18 | ||||
| -rw-r--r-- | source/core/slang-platform.cpp | 22 | ||||
| -rw-r--r-- | source/core/slang-platform.h | 3 | ||||
| -rw-r--r-- | tests/cpp-compiler/c-compile-shared-library.c | 25 | ||||
| -rw-r--r-- | tests/cpp-compiler/c-compile.c (renamed from tests/cross-compile/c-compile.c) | 2 | ||||
| -rw-r--r-- | tests/cpp-compiler/c-compile.c.expected (renamed from tests/cross-compile/c-compile.c.expected) | 0 | ||||
| -rw-r--r-- | tests/cpp-compiler/cpp-compile-shared-library.cpp | 23 | ||||
| -rw-r--r-- | tests/cpp-compiler/cpp-compile.cpp | 9 | ||||
| -rw-r--r-- | tests/cpp-compiler/cpp-compile.cpp.expected | 6 | ||||
| -rw-r--r-- | tools/slang-test/slang-test-main.cpp | 98 |
11 files changed, 229 insertions, 25 deletions
diff --git a/source/core/slang-cpp-compiler.cpp b/source/core/slang-cpp-compiler.cpp index 4bcdd068c..18cb9cdae 100644 --- a/source/core/slang-cpp-compiler.cpp +++ b/source/core/slang-cpp-compiler.cpp @@ -33,7 +33,15 @@ SlangResult GenericCPPCompiler::compile(const CompileOptions& options, ExecuteRe } #endif - return ProcessUtil::execute(cmdLine, outResult); + SlangResult res = ProcessUtil::execute(cmdLine, outResult); + +#if 0 + { + printf("stdout=\"%s\"\nstderr=\"%s\"\nret=%d\n", outResult.standardOutput.getBuffer(), outResult.standardError.getBuffer(), int(outResult.resultCode)); + } +#endif + + return res; } /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CPPCompilerUtil !!!!!!!!!!!!!!!!!!!!!!*/ @@ -153,6 +161,16 @@ SlangResult CPPCompilerUtil::calcGCCFamilyVersion(const String& exeName, CPPComp // Display full path of source files in diagnostics cmdLine.addArg("/FC"); + if (options.flags & CompileOptions::Flag::EnableExceptionHandling) + { + if (options.sourceType == SourceType::CPP) + { + // https://docs.microsoft.com/en-us/cpp/build/reference/eh-exception-handling-model?view=vs-2019 + // Assumes c functions cannot throw + cmdLine.addArg("/EHsc"); + } + } + switch (options.optimizationLevel) { case OptimizationLevel::Debug: @@ -277,28 +295,12 @@ SlangResult CPPCompilerUtil::calcGCCFamilyVersion(const String& exeName, CPPComp { case TargetType::SharedLibrary: { + // Shared library + cmdLine.addArg("-shared"); // Position independent cmdLine.addArg("-fPIC"); - String sharedLibraryPath; - - // Work out the shared library name - { - String moduleDir = Path::getParentDirectory(options.modulePath); - String moduleFilename = Path::getFileName(options.modulePath); - - StringBuilder sharedLibraryFilename; - SharedLibrary::appendPlatformFileName(moduleFilename.getUnownedSlice(), sharedLibraryFilename); - - if (moduleDir.getLength() > 0) - { - sharedLibraryPath = Path::combine(moduleDir, sharedLibraryFilename); - } - else - { - sharedLibraryPath = sharedLibraryFilename; - } - } + String sharedLibraryPath = SharedLibrary::calcPlatformPath(options.modulePath.getUnownedSlice()); cmdLine.addArg("-o"); cmdLine.addArg(sharedLibraryPath); @@ -366,6 +368,12 @@ SlangResult CPPCompilerUtil::calcGCCFamilyVersion(const String& exeName, CPPComp cmdLine.addArg("-F"); cmdLine.addArg(libPath); } + + if (options.sourceType == SourceType::CPP) + { + // Make STD libs available + cmdLine.addArg("-lstdc++"); + } } static CPPCompiler::Desc _calcCompiledWithDesc() diff --git a/source/core/slang-cpp-compiler.h b/source/core/slang-cpp-compiler.h index 82930afd6..83c18bca2 100644 --- a/source/core/slang-cpp-compiler.h +++ b/source/core/slang-cpp-compiler.h @@ -23,6 +23,11 @@ public: GHS, CountOf, }; + enum class SourceType + { + C, ///< C source + CPP, ///< C++ source + }; struct Desc { @@ -70,9 +75,21 @@ public: struct CompileOptions { + typedef uint32_t Flags; + struct Flag + { + enum Enum : Flags + { + EnableExceptionHandling = 0x01, + }; + }; + OptimizationLevel optimizationLevel = OptimizationLevel::Debug; DebugInfoType debugInfoType = DebugInfoType::Normal; TargetType targetType = TargetType::Executable; + SourceType sourceType = SourceType::CPP; + + Flags flags = Flag::EnableExceptionHandling; String modulePath; ///< The path/name of the output module. Should not have the extension, as that will be added for each of the target types @@ -162,6 +179,7 @@ struct CPPCompilerUtil typedef CPPCompiler::OptimizationLevel OptimizationLevel; typedef CPPCompiler::TargetType TargetType; typedef CPPCompiler::DebugInfoType DebugInfoType; + typedef CPPCompiler::SourceType SourceType; enum class MatchType { diff --git a/source/core/slang-platform.cpp b/source/core/slang-platform.cpp index 1cb2bc56e..82f914f7d 100644 --- a/source/core/slang-platform.cpp +++ b/source/core/slang-platform.cpp @@ -2,6 +2,7 @@ #include "slang-platform.h" #include "slang-common.h" +#include "slang-io.h" #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN @@ -25,6 +26,25 @@ namespace Slang return loadWithPlatformFilename(builder.begin(), handleOut); } +/* static */String SharedLibrary::calcPlatformPath(const UnownedStringSlice& path) +{ + // Work out the shared library name + String parent = Path::getParentDirectory(path); + String filename = Path::getFileName(path); + + StringBuilder builder; + SharedLibrary::appendPlatformFileName(filename.getUnownedSlice(), builder); + + if (parent.getLength() > 0) + { + return Path::combine(parent, builder); + } + else + { + return builder; + } +} + #ifdef _WIN32 // Make sure SlangResult match for common standard window HRESULT @@ -105,8 +125,8 @@ SLANG_COMPILE_TIME_ASSERT(E_OUTOFMEMORY == SLANG_E_OUT_OF_MEMORY); /* static */void SharedLibrary::appendPlatformFileName(const UnownedStringSlice& name, StringBuilder& dst) { - // Windows doesn't need the extension or any prefix to work dst.Append(name); + dst.Append(".dll"); } #else // _WIN32 diff --git a/source/core/slang-platform.h b/source/core/slang-platform.h index e33c5599d..31552e42b 100644 --- a/source/core/slang-platform.h +++ b/source/core/slang-platform.h @@ -42,6 +42,9 @@ namespace Slang /// The input name should be unadorned with any 'lib' prefix or extension static void appendPlatformFileName(const UnownedStringSlice& name, StringBuilder& dst); + /// Calculate the shared library + static String calcPlatformPath(const UnownedStringSlice& path); + private: /// Not constructible! SharedLibrary(); diff --git a/tests/cpp-compiler/c-compile-shared-library.c b/tests/cpp-compiler/c-compile-shared-library.c new file mode 100644 index 000000000..8b6be6115 --- /dev/null +++ b/tests/cpp-compiler/c-compile-shared-library.c @@ -0,0 +1,25 @@ +//TEST(smoke):CPP_COMPILER_SHARED_LIBRARY: + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#if defined(_MSC_VER) +# define DLL_EXPORT __declspec(dllexport) +#else +//# define DLL_EXPORT +# define DLL_EXPORT __attribute__ ((dllexport)) __attribute__((__visibility__("default"))) +#endif + +#ifdef __cplusplus +#define EXTERN_C extern "C" +#else +#define EXTERN_C +#endif + +EXTERN_C DLL_EXPORT int test(int intValue, const char* textValue, char* outTextValue) +{ + strcpy(outTextValue, textValue); + return intValue; +} + diff --git a/tests/cross-compile/c-compile.c b/tests/cpp-compiler/c-compile.c index 2151f7474..75fdbdaa4 100644 --- a/tests/cross-compile/c-compile.c +++ b/tests/cpp-compiler/c-compile.c @@ -1,4 +1,4 @@ -//TEST(smoke):EXECUTE_C: +//TEST(smoke):CPP_COMPILER_EXECUTE: #include <stdlib.h> #include <stdio.h> diff --git a/tests/cross-compile/c-compile.c.expected b/tests/cpp-compiler/c-compile.c.expected index 0e042b53b..0e042b53b 100644 --- a/tests/cross-compile/c-compile.c.expected +++ b/tests/cpp-compiler/c-compile.c.expected diff --git a/tests/cpp-compiler/cpp-compile-shared-library.cpp b/tests/cpp-compiler/cpp-compile-shared-library.cpp new file mode 100644 index 000000000..8b70f258d --- /dev/null +++ b/tests/cpp-compiler/cpp-compile-shared-library.cpp @@ -0,0 +1,23 @@ +//TEST(smoke):CPP_COMPILER_SHARED_LIBRARY: + +//#include <slang.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <iostream> +using namespace std; + +#if defined(_MSC_VER) +# define DLL_EXPORT __declspec(dllexport) +#else +# define DLL_EXPORT __attribute__((__visibility__("default"))) +#endif + +extern "C" DLL_EXPORT int test(int intValue, const char* textValue, char* outTextValue) +{ + strcpy(outTextValue, textValue); + return intValue; +} + diff --git a/tests/cpp-compiler/cpp-compile.cpp b/tests/cpp-compiler/cpp-compile.cpp new file mode 100644 index 000000000..c3141a876 --- /dev/null +++ b/tests/cpp-compiler/cpp-compile.cpp @@ -0,0 +1,9 @@ +//TEST(smoke):CPP_COMPILER_EXECUTE: +#include <iostream> +using namespace std; + +int main(int argc, char** argv) +{ + cout << "Hello World!" << endl; + return 0; +} diff --git a/tests/cpp-compiler/cpp-compile.cpp.expected b/tests/cpp-compiler/cpp-compile.cpp.expected new file mode 100644 index 000000000..0e042b53b --- /dev/null +++ b/tests/cpp-compiler/cpp-compile.cpp.expected @@ -0,0 +1,6 @@ +result code = 0 +standard error = { +} +standard output = { +Hello World! +} diff --git a/tools/slang-test/slang-test-main.cpp b/tools/slang-test/slang-test-main.cpp index 0777c31f2..e792abe72 100644 --- a/tools/slang-test/slang-test-main.cpp +++ b/tools/slang-test/slang-test-main.cpp @@ -1086,7 +1086,7 @@ String getExpectedOutput(String const& outputStem) return expectedOutput; } -static TestResult runExecuteC(TestContext* context, TestInput& input) +static TestResult runCPPCompilerExecute(TestContext* context, TestInput& input) { CPPCompilerSet* compilerSet = context->getCPPCompilerSet(); CPPCompiler* compiler = compilerSet ? compilerSet->getDefaultCompiler() : nullptr; @@ -1111,7 +1111,7 @@ static TestResult runExecuteC(TestContext* context, TestInput& input) // Make the module name the same as the source file String directory = Path::getParentDirectory(input.outputStem); String moduleName = Path::getFileNameWithoutExt(filePath); - + String ext = Path::getFileExt(filePath); String modulePath = Path::combine(directory, moduleName); // Remove the binary.. @@ -1125,6 +1125,8 @@ static TestResult runExecuteC(TestContext* context, TestInput& input) // Set up the compilation options CPPCompiler::CompileOptions options; + options.sourceType = (ext == "c") ? CPPCompiler::SourceType::C : CPPCompiler::SourceType::CPP; + // Compile this source options.sourceFiles.add(filePath); options.modulePath = modulePath; @@ -1177,6 +1179,95 @@ static TestResult runExecuteC(TestContext* context, TestInput& input) return TestResult::Pass; } +static TestResult runCPPCompilerSharedLibrary(TestContext* context, TestInput& input) +{ + CPPCompilerSet* compilerSet = context->getCPPCompilerSet(); + CPPCompiler* compiler = compilerSet ? compilerSet->getDefaultCompiler() : nullptr; + + if (!compiler) + { + return TestResult::Ignored; + } + + // If we are just collecting requirements, say it passed + if (context->isCollectingRequirements()) + { + return TestResult::Pass; + } + + auto filePath = input.filePath; + auto outputStem = input.outputStem; + + String actualOutputPath = outputStem + ".actual"; + File::remove(actualOutputPath); + + // Make the module name the same as the source file + String directory = Path::getParentDirectory(input.outputStem); + String moduleName = Path::getFileNameWithoutExt(filePath); + String ext = Path::getFileExt(filePath); + + String modulePath = Path::combine(directory, moduleName); + + // Remove the binary.. + String sharedLibraryPath = SharedLibrary::calcPlatformPath(modulePath.getUnownedSlice()); + File::remove(sharedLibraryPath); + + // Set up the compilation options + CPPCompiler::CompileOptions options; + + options.sourceType = (ext == "c") ? CPPCompiler::SourceType::C : CPPCompiler::SourceType::CPP; + + // Build a shared library + options.targetType = CPPCompiler::TargetType::SharedLibrary; + + // Compile this source + options.sourceFiles.add(filePath); + options.modulePath = modulePath; + + options.includePaths.add("."); + + ExecuteResult exeRes; + + if (SLANG_FAILED(compiler->compile(options, exeRes))) + { + return TestResult::Fail; + } + + SharedLibrary::Handle handle; + if (SLANG_FAILED(SharedLibrary::loadWithPlatformFilename(sharedLibraryPath.getBuffer(), handle))) + { + return TestResult::Fail; + } + + const int inValue = 10; + const char inBuffer[] = "Hello World!"; + + char buffer[128] = ""; + int value = 0; + + typedef int (*TestFunc)(int intValue, const char* textValue, char* outTextValue); + + // We could capture output if we passed in a ISlangWriter - but for that to work we'd need a + TestFunc testFunc = (TestFunc)SharedLibrary::findFuncByName(handle, "test"); + if (testFunc) + { + value = testFunc(inValue, inBuffer, buffer); + } + else + { + printf("Unable to access 'test' function\n"); + } + + SharedLibrary::unload(handle); + + if (!(inValue == value && strcmp(inBuffer, buffer) == 0)) + { + return TestResult::Fail; + } + + return TestResult::Pass; +} + TestResult runCrossCompilerTest(TestContext* context, TestInput& input) { // need to execute the stand-alone Slang compiler on the file @@ -1983,7 +2074,8 @@ static const TestCommandInfo s_testCommandInfos[] = { "COMPARE_RENDER_COMPUTE", &runSlangRenderComputeComparisonTest}, { "COMPARE_GLSL", &runGLSLComparisonTest}, { "CROSS_COMPILE", &runCrossCompilerTest}, - { "EXECUTE_C", &runExecuteC}, + { "CPP_COMPILER_EXECUTE", &runCPPCompilerExecute}, + { "CPP_COMPILER_SHARED_LIBRARY", &runCPPCompilerSharedLibrary}, }; TestResult runTest( |
