Build SPIRV-Tools as shared library
authorJózef Kucia <joseph.kucia@gmail.com>
Fri, 2 Feb 2018 22:37:14 +0000 (23:37 +0100)
committerDavid Neto <dneto@google.com>
Wed, 7 Feb 2018 15:43:32 +0000 (10:43 -0500)
Add pkg-config file for shared libraries

Properly build SPIRV-Tools DLL

Test C interface with shared library

Set PATH to shared library file for c_interface_shared test

Otherwise, the test won't find SPIRV-Tools-shared.dll.

Do not use private functions when testing with shared library

Make all symbols hidden by default for shared library target

CMakeLists.txt
cmake/SPIRV-Tools-shared.pc.in [new file with mode: 0644]
include/spirv-tools/libspirv.h
source/CMakeLists.txt
test/CMakeLists.txt
test/c_interface_test.cpp

index e76a663..011baf9 100644 (file)
@@ -222,6 +222,7 @@ if (NOT "${SPIRV_SKIP_TESTS}")
 endif()
 
 set(SPIRV_LIBRARIES "-lSPIRV-Tools -lSPIRV-Tools-link -lSPIRV-Tools-opt")
+set(SPIRV_SHARED_LIBRARIES "-lSPIRV-Tools-shared")
 if(SPIRV_BUILD_COMPRESSION)
   set(SPIRV_LIBRARIES "${SPIRV_LIBRARIES} -lSPIRV-Tools-comp")
 endif(SPIRV_BUILD_COMPRESSION)
@@ -236,12 +237,21 @@ add_custom_target(spirv-tools-pkg-config ALL
                       -DSPIRV_LIBRARIES=${SPIRV_LIBRARIES}
                       -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/write_pkg_config.cmake
         DEPENDS "CHANGES" "cmake/SPIRV-Tools.pc.in" "cmake/write_pkg_config.cmake")
+add_custom_target(spirv-tools-shared-pkg-config ALL
+        COMMAND cmake -DCHANGES_FILE=${CMAKE_CURRENT_SOURCE_DIR}/CHANGES
+                      -DTEMPLATE_FILE=${CMAKE_CURRENT_SOURCE_DIR}/cmake/SPIRV-Tools-shared.pc.in
+                      -DOUT_FILE=${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools-shared.pc
+                      -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
+                      -DSPIRV_SHARED_LIBRARIES=${SPIRV_SHARED_LIBRARIES}
+                      -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/write_pkg_config.cmake
+        DEPENDS "CHANGES" "cmake/SPIRV-Tools-shared.pc.in" "cmake/write_pkg_config.cmake")
 
 # Install pkg-config file
 if (ENABLE_SPIRV_TOOLS_INSTALL)
   install(
     FILES
       ${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools.pc
+      ${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools-shared.pc
     DESTINATION
       ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
 endif()
diff --git a/cmake/SPIRV-Tools-shared.pc.in b/cmake/SPIRV-Tools-shared.pc.in
new file mode 100644 (file)
index 0000000..3c1c8aa
--- /dev/null
@@ -0,0 +1,12 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=${prefix}/lib64
+includedir=${prefix}/include
+
+Name: SPIRV-Tools
+Description: Tools for SPIR-V
+Version: @CURRENT_VERSION@
+URL: https://github.com/KhronosGroup/SPIRV-Tools
+
+Libs: -L${libdir} @SPIRV_SHARED_LIBRARIES@
+Cflags: -I${includedir}
index e8ff4a5..7f1ebba 100644 (file)
@@ -24,6 +24,24 @@ extern "C" {
 #include <stddef.h>
 #include <stdint.h>
 
+#if defined(SPIRV_TOOLS_SHAREDLIB)
+#if defined(_WIN32)
+#if defined(SPIRV_TOOLS_IMPLEMENTATION)
+#define SPIRV_TOOLS_EXPORT __declspec(dllexport)
+#else
+#define SPIRV_TOOLS_EXPORT __declspec(dllimport)
+#endif
+#else
+#if defined(SPIRV_TOOLS_IMPLEMENTATION)
+#define SPIRV_TOOLS_EXPORT __attribute__((visibility("default")))
+#else
+#define SPIRV_TOOLS_EXPORT
+#endif
+#endif
+#else
+#define SPIRV_TOOLS_EXPORT
+#endif
+
 // Helpers
 
 #define SPV_BIT(shift) (1 << (shift))
@@ -358,12 +376,12 @@ typedef const spv_validator_options_t* spv_const_validator_options;
 // Returns the SPIRV-Tools software version as a null-terminated string.
 // The contents of the underlying storage is valid for the remainder of
 // the process.
-const char* spvSoftwareVersionString();
+SPIRV_TOOLS_EXPORT const char* spvSoftwareVersionString();
 // Returns a null-terminated string containing the name of the project,
 // the software version string, and commit details.
 // The contents of the underlying storage is valid for the remainder of
 // the process.
-const char* spvSoftwareVersionDetailsString();
+SPIRV_TOOLS_EXPORT const char* spvSoftwareVersionDetailsString();
 
 // Certain target environments impose additional restrictions on SPIR-V, so it's
 // often necessary to specify which one applies.  SPV_ENV_UNIVERSAL means
@@ -406,27 +424,28 @@ typedef enum {
 } spv_validator_limit;
 
 // Returns a string describing the given SPIR-V target environment.
-const char* spvTargetEnvDescription(spv_target_env env);
+SPIRV_TOOLS_EXPORT const char* spvTargetEnvDescription(spv_target_env env);
 
 // Creates a context object.  Returns null if env is invalid.
-spv_context spvContextCreate(spv_target_env env);
+SPIRV_TOOLS_EXPORT spv_context spvContextCreate(spv_target_env env);
 
 // Destroys the given context object.
-void spvContextDestroy(spv_context context);
+SPIRV_TOOLS_EXPORT void spvContextDestroy(spv_context context);
 
 // Creates a Validator options object with default options. Returns a valid
 // options object. The object remains valid until it is passed into
 // spvValidatorOptionsDestroy.
-spv_validator_options spvValidatorOptionsCreate();
+SPIRV_TOOLS_EXPORT spv_validator_options spvValidatorOptionsCreate();
 
 // Destroys the given Validator options object.
-void spvValidatorOptionsDestroy(spv_validator_options options);
+SPIRV_TOOLS_EXPORT void spvValidatorOptionsDestroy(
+    spv_validator_options options);
 
 // Records the maximum Universal Limit that is considered valid in the given
 // Validator options object. <options> argument must be a valid options object.
-void spvValidatorOptionsSetUniversalLimit(spv_validator_options options,
-                                          spv_validator_limit limit_type,
-                                          uint32_t limit);
+SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetUniversalLimit(
+    spv_validator_options options, spv_validator_limit limit_type,
+    uint32_t limit);
 
 // Record whether or not the validator should relax the rules on types for
 // stores to structs.  When relaxed, it will allow a type mismatch as long as
@@ -438,8 +457,8 @@ void spvValidatorOptionsSetUniversalLimit(spv_validator_options options,
 //
 // 2) the decorations that affect the memory layout are identical for both
 // types.  Other decorations are not relevant.
-void spvValidatorOptionsSetRelaxStoreStruct(spv_validator_options options,
-                                            bool val);
+SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetRelaxStoreStruct(
+    spv_validator_options options, bool val);
 
 // Records whether or not the validator should relax the rules on pointer usage
 // in logical addressing mode.
@@ -447,77 +466,79 @@ void spvValidatorOptionsSetRelaxStoreStruct(spv_validator_options options,
 // When relaxed, it will allow the following usage cases of pointers:
 // 1) OpVariable allocating an object whose type is a pointer type
 // 2) OpReturnValue returning a pointer value
-void spvValidatorOptionsSetRelaxLogicalPointer(spv_validator_options options,
-                                               bool val);
+SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetRelaxLogicalPointer(
+    spv_validator_options options, bool val);
 
 // Encodes the given SPIR-V assembly text to its binary representation. The
 // length parameter specifies the number of bytes for text. Encoded binary will
 // be stored into *binary. Any error will be written into *diagnostic if
 // diagnostic is non-null. The generated binary is independent of the context
 // and may outlive it.
-spv_result_t spvTextToBinary(const spv_const_context context, const char* text,
-                             const size_t length, spv_binary* binary,
-                             spv_diagnostic* diagnostic);
+SPIRV_TOOLS_EXPORT spv_result_t spvTextToBinary(const spv_const_context context,
+                                                const char* text,
+                                                const size_t length,
+                                                spv_binary* binary,
+                                                spv_diagnostic* diagnostic);
 
 // Encodes the given SPIR-V assembly text to its binary representation. Same as
 // spvTextToBinary but with options. The options parameter is a bit field of
 // spv_text_to_binary_options_t.
-spv_result_t spvTextToBinaryWithOptions(const spv_const_context context,
-                                        const char* text, const size_t length,
-                                        const uint32_t options,
-                                        spv_binary* binary,
-                                        spv_diagnostic* diagnostic);
+SPIRV_TOOLS_EXPORT spv_result_t spvTextToBinaryWithOptions(
+    const spv_const_context context, const char* text, const size_t length,
+    const uint32_t options, spv_binary* binary, spv_diagnostic* diagnostic);
 
 // Frees an allocated text stream. This is a no-op if the text parameter
 // is a null pointer.
-void spvTextDestroy(spv_text text);
+SPIRV_TOOLS_EXPORT void spvTextDestroy(spv_text text);
 
 // Decodes the given SPIR-V binary representation to its assembly text. The
 // word_count parameter specifies the number of words for binary. The options
 // parameter is a bit field of spv_binary_to_text_options_t. Decoded text will
 // be stored into *text. Any error will be written into *diagnostic if
 // diagnostic is non-null.
-spv_result_t spvBinaryToText(const spv_const_context context,
-                             const uint32_t* binary, const size_t word_count,
-                             const uint32_t options, spv_text* text,
-                             spv_diagnostic* diagnostic);
+SPIRV_TOOLS_EXPORT spv_result_t spvBinaryToText(const spv_const_context context,
+                                                const uint32_t* binary,
+                                                const size_t word_count,
+                                                const uint32_t options,
+                                                spv_text* text,
+                                                spv_diagnostic* diagnostic);
 
 // Frees a binary stream from memory. This is a no-op if binary is a null
 // pointer.
-void spvBinaryDestroy(spv_binary binary);
+SPIRV_TOOLS_EXPORT void spvBinaryDestroy(spv_binary binary);
 
 // Validates a SPIR-V binary for correctness. Any errors will be written into
 // *diagnostic if diagnostic is non-null.
-spv_result_t spvValidate(const spv_const_context context,
-                         const spv_const_binary binary,
-                         spv_diagnostic* diagnostic);
+SPIRV_TOOLS_EXPORT spv_result_t spvValidate(const spv_const_context context,
+                                            const spv_const_binary binary,
+                                            spv_diagnostic* diagnostic);
 
 // Validates a SPIR-V binary for correctness. Uses the provided Validator
 // options. Any errors will be written into *diagnostic if diagnostic is
 // non-null.
-spv_result_t spvValidateWithOptions(const spv_const_context context,
-                                    const spv_const_validator_options options,
-                                    const spv_const_binary binary,
-                                    spv_diagnostic* diagnostic);
+SPIRV_TOOLS_EXPORT spv_result_t spvValidateWithOptions(
+    const spv_const_context context, const spv_const_validator_options options,
+    const spv_const_binary binary, spv_diagnostic* diagnostic);
 
 // Validates a raw SPIR-V binary for correctness. Any errors will be written
 // into *diagnostic if diagnostic is non-null.
-spv_result_t spvValidateBinary(const spv_const_context context,
-                               const uint32_t* words, const size_t num_words,
-                               spv_diagnostic* diagnostic);
+SPIRV_TOOLS_EXPORT spv_result_t
+spvValidateBinary(const spv_const_context context, const uint32_t* words,
+                  const size_t num_words, spv_diagnostic* diagnostic);
 
 // Creates a diagnostic object. The position parameter specifies the location in
 // the text/binary stream. The message parameter, copied into the diagnostic
 // object, contains the error message to display.
-spv_diagnostic spvDiagnosticCreate(const spv_position position,
-                                   const char* message);
+SPIRV_TOOLS_EXPORT spv_diagnostic
+spvDiagnosticCreate(const spv_position position, const char* message);
 
 // Destroys a diagnostic object.  This is a no-op if diagnostic is a null
 // pointer.
-void spvDiagnosticDestroy(spv_diagnostic diagnostic);
+SPIRV_TOOLS_EXPORT void spvDiagnosticDestroy(spv_diagnostic diagnostic);
 
 // Prints the diagnostic to stderr.
-spv_result_t spvDiagnosticPrint(const spv_diagnostic diagnostic);
+SPIRV_TOOLS_EXPORT spv_result_t
+spvDiagnosticPrint(const spv_diagnostic diagnostic);
 
 // The binary parser interface.
 
@@ -550,11 +571,10 @@ typedef spv_result_t (*spv_parsed_instruction_fn_t)(
 // also emits a diagnostic.  If a callback returns anything other than
 // SPV_SUCCESS, then that status code is returned, no further callbacks are
 // issued, and no additional diagnostics are emitted.
-spv_result_t spvBinaryParse(const spv_const_context context, void* user_data,
-                            const uint32_t* words, const size_t num_words,
-                            spv_parsed_header_fn_t parse_header,
-                            spv_parsed_instruction_fn_t parse_instruction,
-                            spv_diagnostic* diagnostic);
+SPIRV_TOOLS_EXPORT spv_result_t spvBinaryParse(
+    const spv_const_context context, void* user_data, const uint32_t* words,
+    const size_t num_words, spv_parsed_header_fn_t parse_header,
+    spv_parsed_instruction_fn_t parse_instruction, spv_diagnostic* diagnostic);
 
 #ifdef __cplusplus
 }
index d8f1d67..b01edf5 100644 (file)
@@ -334,8 +334,23 @@ target_include_directories(${SPIRV_TOOLS}
 set_property(TARGET ${SPIRV_TOOLS} PROPERTY FOLDER "SPIRV-Tools libraries")
 spvtools_check_symbol_exports(${SPIRV_TOOLS})
 
+add_library(${SPIRV_TOOLS}-shared SHARED ${SPIRV_SOURCES})
+spvtools_default_compile_options(${SPIRV_TOOLS}-shared)
+target_include_directories(${SPIRV_TOOLS}-shared
+  PUBLIC ${spirv-tools_SOURCE_DIR}/include
+  PRIVATE ${spirv-tools_BINARY_DIR}
+  PRIVATE ${SPIRV_HEADER_INCLUDE_DIR}
+  )
+set_target_properties(${SPIRV_TOOLS}-shared PROPERTIES CXX_VISIBILITY_PRESET hidden)
+set_property(TARGET ${SPIRV_TOOLS}-shared PROPERTY FOLDER "SPIRV-Tools libraries")
+spvtools_check_symbol_exports(${SPIRV_TOOLS}-shared)
+target_compile_definitions(${SPIRV_TOOLS}-shared
+  PRIVATE SPIRV_TOOLS_IMPLEMENTATION
+  PUBLIC SPIRV_TOOLS_SHAREDLIB
+)
+
 if(ENABLE_SPIRV_TOOLS_INSTALL)
-  install(TARGETS ${SPIRV_TOOLS}
+  install(TARGETS ${SPIRV_TOOLS} ${SPIRV_TOOLS}-shared
     RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
     LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
     ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
index 4ede989..13889cd 100644 (file)
@@ -31,7 +31,7 @@ endif()
 function(add_spvtools_unittest)
   if (NOT "${SPIRV_SKIP_TESTS}" AND TARGET gmock_main)
     set(one_value_args TARGET)
-    set(multi_value_args SRCS LIBS)
+    set(multi_value_args SRCS LIBS ENVIRONMENT)
     cmake_parse_arguments(
       ARG "" "${one_value_args}" "${multi_value_args}" ${ARGN})
     set(target test_${ARG_TARGET})
@@ -72,6 +72,9 @@ function(add_spvtools_unittest)
     endif()
     target_link_libraries(${target} PRIVATE gmock_main)
     add_test(NAME spirv-tools-${target} COMMAND ${target})
+    if (DEFINED ARG_ENVIRONMENT)
+      set_tests_properties(spirv-tools-${target} PROPERTIES ENVIRONMENT ${ARG_ENVIRONMENT})
+    endif()
     set_property(TARGET ${target} PROPERTY FOLDER "SPIRV-Tools tests")
   endif()
 endfunction()
@@ -154,6 +157,12 @@ add_spvtools_unittest(
   LIBS ${SPIRV_TOOLS})
 
 add_spvtools_unittest(
+  TARGET c_interface_shared
+  SRCS c_interface_test.cpp
+  LIBS ${SPIRV_TOOLS}-shared
+  ENVIRONMENT PATH=$<TARGET_FILE_DIR:${SPIRV_TOOLS}-shared>)
+
+add_spvtools_unittest(
   TARGET cpp_interface
   SRCS cpp_interface_test.cpp
   LIBS SPIRV-Tools-opt)
index 9d1ad1f..9260549 100644 (file)
@@ -22,7 +22,15 @@ namespace {
 
 using namespace spvtools;
 
-using libspirv::SetContextMessageConsumer;
+// TODO(antiagainst): Use public C API for setting the consumer once exists.
+#ifndef SPIRV_TOOLS_SHAREDLIB
+void SetContextMessageConsumer(spv_context context,
+                               spvtools::MessageConsumer consumer) {
+  libspirv::SetContextMessageConsumer(context, consumer);
+}
+#else
+void SetContextMessageConsumer(spv_context, spvtools::MessageConsumer) {}
+#endif
 
 // The default consumer is a null std::function.
 TEST(CInterface, DefaultConsumerNullDiagnosticForValidInput) {
@@ -107,7 +115,6 @@ TEST(CInterface, SpecifyConsumerNullDiagnosticForAssembling) {
 
   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
   int invocation = 0;
-  // TODO(antiagainst): Use public C API for setting the consumer once exists.
   SetContextMessageConsumer(
       context,
       [&invocation](spv_message_level_t level, const char* source,
@@ -126,7 +133,9 @@ TEST(CInterface, SpecifyConsumerNullDiagnosticForAssembling) {
   EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
             spvTextToBinary(context, input_text, sizeof(input_text), &binary,
                             nullptr));
+#ifndef SPIRV_TOOLS_SHAREDLIB
   EXPECT_EQ(1, invocation);
+#endif
   spvBinaryDestroy(binary);
   spvContextDestroy(context);
 }
@@ -159,7 +168,9 @@ TEST(CInterface, SpecifyConsumerNullDiagnosticForDisassembling) {
   EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
             spvBinaryToText(context, binary->code, binary->wordCount, 0, &text,
                             nullptr));
+#ifndef SPIRV_TOOLS_SHAREDLIB
   EXPECT_EQ(1, invocation);
+#endif
 
   spvTextDestroy(text);
   spvBinaryDestroy(binary);
@@ -193,7 +204,9 @@ TEST(CInterface, SpecifyConsumerNullDiagnosticForValidating) {
 
   spv_const_binary_t b{binary->code, binary->wordCount};
   EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, spvValidate(context, &b, nullptr));
+#ifndef SPIRV_TOOLS_SHAREDLIB
   EXPECT_EQ(1, invocation);
+#endif
 
   spvBinaryDestroy(binary);
   spvContextDestroy(context);