You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@parquet.apache.org by we...@apache.org on 2016/07/01 21:45:20 UTC

parquet-cpp git commit: PARQUET-489: Shared library symbol visibility

Repository: parquet-cpp
Updated Branches:
  refs/heads/master 9da725002 -> f97042d9b


PARQUET-489: Shared library symbol visibility

This was a bit of rabbit hole, because on Linux you must instruct gcc how to hide symbols from your static thirdparty libraries (see `src/parquet/symbols.map`). I learned about this from Apache Kudu (incubating) client cmake files.

Probably still a bit more to do here (and I may have missed some things we should export, and exporting things that should not be exported); I will make sure the Arrow-Parquet tests still pass, but wanted to get some early feedback.

Author: Wes McKinney <we...@apache.org>

Closes #131 from wesm/PARQUET-489 and squashes the following commits:

2cd834a [Wes McKinney] Link static libs to all executables
ed47d1e [Wes McKinney] Hide more symbols when statically-linking libstdc++
d052387 [Wes McKinney] Correctly export default_allocator
9f17ea3 [Wes McKinney] Install visibility.h
9d97985 [Wes McKinney] - Adapt symbol.map from Kudu to hide thirdparty static deps - Link tests to static lib - Add visibility header - First cut exports


Project: http://git-wip-us.apache.org/repos/asf/parquet-cpp/repo
Commit: http://git-wip-us.apache.org/repos/asf/parquet-cpp/commit/f97042d9
Tree: http://git-wip-us.apache.org/repos/asf/parquet-cpp/tree/f97042d9
Diff: http://git-wip-us.apache.org/repos/asf/parquet-cpp/diff/f97042d9

Branch: refs/heads/master
Commit: f97042d9bab10fffdb5e532fcc21a9ccc27f4f1c
Parents: 9da7250
Author: Wes McKinney <we...@apache.org>
Authored: Fri Jul 1 14:45:13 2016 -0700
Committer: Wes McKinney <we...@apache.org>
Committed: Fri Jul 1 14:45:13 2016 -0700

----------------------------------------------------------------------
 CMakeLists.txt                   | 95 ++++++++++++++++++++---------------
 example/CMakeLists.txt           | 21 +++-----
 src/parquet/column/levels.cc     |  3 +-
 src/parquet/column/properties.h  |  9 ++--
 src/parquet/column/reader.h      |  5 +-
 src/parquet/column/scanner.h     |  5 +-
 src/parquet/column/writer.h      |  5 +-
 src/parquet/exception.h          |  2 +
 src/parquet/file/reader.h        |  5 +-
 src/parquet/file/writer.h        |  5 +-
 src/parquet/schema/descriptor.h  |  5 +-
 src/parquet/schema/printer.h     |  5 +-
 src/parquet/schema/types.h       | 10 ++--
 src/parquet/symbols.map          | 34 +++++++++++++
 src/parquet/types.h              |  1 +
 src/parquet/util/CMakeLists.txt  |  1 +
 src/parquet/util/buffer.h        |  9 ++--
 src/parquet/util/input.h         | 13 ++---
 src/parquet/util/mem-allocator.h |  8 +--
 src/parquet/util/output.h        |  7 +--
 src/parquet/util/visibility.h    | 32 ++++++++++++
 21 files changed, 187 insertions(+), 93 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/parquet-cpp/blob/f97042d9/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4df9239..f2c08cb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -55,7 +55,7 @@ option(PARQUET_BUILD_SHARED
     ON)
 option(PARQUET_BUILD_STATIC
     "Build the static version of libparquet"
-    OFF)
+    ON)
 
 # if no build build type is specified, default to debug builds
 if (NOT CMAKE_BUILD_TYPE)
@@ -68,20 +68,20 @@ string (TOLOWER ${CMAKE_BUILD_TYPE} BUILD_SUBDIR_NAME)
 # Top level cmake file, set options
 if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
   option(PARQUET_USE_SSE
-	"Build with SSE4 optimizations"
-	OFF)
+    "Build with SSE4 optimizations"
+    OFF)
   option(PARQUET_BUILD_BENCHMARKS
-	"Build the libparquet benchmark suite"
+    "Build the libparquet benchmark suite"
     OFF)
   option(PARQUET_BUILD_TESTS
-	"Build the libparquet test suite"
-	ON)
+    "Build the libparquet test suite"
+    ON)
   option(PARQUET_TEST_MEMCHECK
-	"Run the test suite using valgrind --tool=memcheck"
-	OFF)
+    "Run the test suite using valgrind --tool=memcheck"
+    OFF)
   option(PARQUET_BUILD_EXECUTABLES
-	"Build the libparquet executable CLI tools"
-	ON)
+    "Build the libparquet executable CLI tools"
+    ON)
 endif()
 
 # If build in-source, create the latest symlink. If build out-of-source, which is
@@ -171,7 +171,7 @@ endfunction()
 #
 # Arguments after the test name will be passed to set_tests_properties().
 function(ADD_PARQUET_TEST REL_TEST_NAME)
-  if(NOT PARQUET_BUILD_TESTS)
+  if(NOT PARQUET_BUILD_TESTS OR NOT PARQUET_BUILD_STATIC)
     return()
   endif()
   get_filename_component(TEST_NAME ${REL_TEST_NAME} NAME_WE)
@@ -182,15 +182,15 @@ function(ADD_PARQUET_TEST REL_TEST_NAME)
     add_executable(${TEST_NAME} "${REL_TEST_NAME}.cc")
     add_dependencies(unittest ${TEST_NAME})
 
-	if(APPLE)
-	  # On OS X / Thrift >= 0.9.2, tr1/tuple.h is not in libc++
-	  SET_TARGET_PROPERTIES(${TEST_NAME} PROPERTIES COMPILE_FLAGS
-		-DGTEST_USE_OWN_TR1_TUPLE=1)
-	else()
-	  # Linux, for Thrift >= 0.9.2
-	  SET_TARGET_PROPERTIES(${TEST_NAME} PROPERTIES COMPILE_FLAGS
-		-DGTEST_USE_OWN_TR1_TUPLE=0)
-	endif()
+    if(APPLE)
+      # On OS X / Thrift >= 0.9.2, tr1/tuple.h is not in libc++
+      SET_TARGET_PROPERTIES(${TEST_NAME} PROPERTIES COMPILE_FLAGS
+        -DGTEST_USE_OWN_TR1_TUPLE=1)
+    else()
+      # Linux, for Thrift >= 0.9.2
+      SET_TARGET_PROPERTIES(${TEST_NAME} PROPERTIES COMPILE_FLAGS
+        -DGTEST_USE_OWN_TR1_TUPLE=0)
+    endif()
 
     target_link_libraries(${TEST_NAME} ${PARQUET_TEST_LINK_LIBS})
   else()
@@ -199,13 +199,13 @@ function(ADD_PARQUET_TEST REL_TEST_NAME)
   endif()
 
   if (PARQUET_TEST_MEMCHECK)
-	SET_PROPERTY(TARGET ${TEST_NAME}
-	  APPEND_STRING PROPERTY
-	  COMPILE_FLAGS " -DPARQUET_VALGRIND")
-	add_test(${TEST_NAME}
-	  valgrind --tool=memcheck --leak-check=full --error-exitcode=1 ${TEST_PATH})
+    SET_PROPERTY(TARGET ${TEST_NAME}
+      APPEND_STRING PROPERTY
+      COMPILE_FLAGS " -DPARQUET_VALGRIND")
+    add_test(${TEST_NAME}
+      valgrind --tool=memcheck --leak-check=full --error-exitcode=1 ${TEST_PATH})
   else()
-	add_test(${TEST_NAME}
+    add_test(${TEST_NAME}
         ${BUILD_SUPPORT_DIR}/run-test.sh ${CMAKE_BINARY_DIR} test ${TEST_PATH})
   endif()
   set_tests_properties(${TEST_NAME} PROPERTIES LABELS "unittest")
@@ -320,6 +320,7 @@ string (TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE)
 
 if ("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG")
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_FLAGS_DEBUG}")
+
 elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "FASTDEBUG")
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_FLAGS_FASTDEBUG}")
 elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE")
@@ -356,6 +357,15 @@ if ("${COMPILER_FAMILY}" STREQUAL "clang")
 endif()
 
 ############################################################
+# Visibility
+############################################################
+# For generate_export_header() and add_compiler_export_flags().
+include(GenerateExportHeader)
+
+# Sets -fvisibility=hidden for gcc
+add_compiler_export_flags()
+
+############################################################
 # Includes
 
 include_directories(
@@ -406,15 +416,10 @@ endif()
 #############################################################
 # Test linking
 
-if (PARQUET_BUILD_STATIC)
-    set(PARQUET_MIN_TEST_LIBS
-      parquet_test_main
-      parquet_static)
-else()
-    set(PARQUET_MIN_TEST_LIBS
-      parquet_test_main
-      parquet_shared)
-endif()
+set(PARQUET_MIN_TEST_LIBS
+  parquet_test_main
+  parquet_static)
+
 set(PARQUET_TEST_LINK_LIBS ${PARQUET_MIN_TEST_LIBS})
 
 #############################################################
@@ -447,7 +452,7 @@ if ("${PARQUET_GENERATE_COVERAGE}")
   # __gcov_flush() doesn't properly flush coverage from every module.
   # See http://stackoverflow.com/questions/28164543/using-gcov-flush-within-a-library-doesnt-force-the-other-modules-to-yield-gc
   if(NOT PARQUET_BUILD_STATIC)
-    message(SEND_ERROR "Cannot use coverage with dynamic linking")
+    message(SEND_ERROR "Coverage requires the static lib to be built")
   endif()
 endif()
 
@@ -500,6 +505,13 @@ add_library(parquet_objlib OBJECT
 
 set_property(TARGET parquet_objlib PROPERTY POSITION_INDEPENDENT_CODE 1)
 
+if(NOT APPLE)
+  # Localize thirdparty symbols using a linker version script. This hides them
+  # from the client application. The OS X linker does not support the
+  # version-script option.
+  set(SHARED_LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/src/parquet/symbols.map")
+endif()
+
 if (PARQUET_BUILD_SHARED)
     add_library(parquet_shared SHARED $<TARGET_OBJECTS:parquet_objlib>)
     if(APPLE)
@@ -508,9 +520,11 @@ if (PARQUET_BUILD_SHARED)
     set_target_properties(parquet_shared
       PROPERTIES
       LIBRARY_OUTPUT_DIRECTORY "${BUILD_OUTPUT_ROOT_DIRECTORY}"
+      LINK_FLAGS "${SHARED_LINK_FLAGS}"
       OUTPUT_NAME "parquet")
-    target_link_libraries(parquet_shared LINK_PUBLIC ${LIBPARQUET_LINK_LIBS})
-    target_link_libraries(parquet_shared LINK_PRIVATE ${LIBPARQUET_PRIVATE_LINK_LIBS})
+    target_link_libraries(parquet_shared
+      LINK_PUBLIC ${LIBPARQUET_LINK_LIBS}
+      LINK_PRIVATE ${LIBPARQUET_PRIVATE_LINK_LIBS})
 endif()
 
 if (PARQUET_BUILD_STATIC)
@@ -519,8 +533,9 @@ if (PARQUET_BUILD_STATIC)
       PROPERTIES
       LIBRARY_OUTPUT_DIRECTORY "${BUILD_OUTPUT_ROOT_DIRECTORY}"
       OUTPUT_NAME "parquet")
-    target_link_libraries(parquet_static LINK_PUBLIC ${LIBPARQUET_LINK_LIBS})
-    target_link_libraries(parquet_static LINK_PRIVATE ${LIBPARQUET_PRIVATE_LINK_LIBS})
+    target_link_libraries(parquet_static
+	  LINK_PUBLIC ${LIBPARQUET_LINK_LIBS}
+	  LINK_PRIVATE ${LIBPARQUET_PRIVATE_LINK_LIBS})
 endif()
 
 add_subdirectory(src/parquet)

http://git-wip-us.apache.org/repos/asf/parquet-cpp/blob/f97042d9/example/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt
index 4b02f81..d622d09 100644
--- a/example/CMakeLists.txt
+++ b/example/CMakeLists.txt
@@ -19,23 +19,18 @@ SET(LINK_LIBS
   snappystatic
   thriftstatic)
 
-if (PARQUET_BUILD_STATIC)
-    SET(LINK_LIBS
-        ${LINK_LIBS}
-        parquet_static)
-else ()
-    SET(LINK_LIBS
-        ${LINK_LIBS}
-        parquet_shared)
-endif()
-
 if (PARQUET_BUILD_EXECUTABLES)
   add_executable(decode_benchmark decode_benchmark.cc)
-  target_link_libraries(decode_benchmark ${LINK_LIBS})
+
+  # This uses private APIs
+  target_link_libraries(decode_benchmark ${LINK_LIBS}
+	parquet_static)
 
   add_executable(parquet-dump-schema parquet-dump-schema.cc)
-  target_link_libraries(parquet-dump-schema ${LINK_LIBS})
+  target_link_libraries(parquet-dump-schema ${LINK_LIBS}
+	parquet_static)
 
   add_executable(parquet_reader parquet_reader.cc)
-  target_link_libraries(parquet_reader ${LINK_LIBS})
+  target_link_libraries(parquet_reader ${LINK_LIBS}
+	parquet_static)
 endif()

http://git-wip-us.apache.org/repos/asf/parquet-cpp/blob/f97042d9/src/parquet/column/levels.cc
----------------------------------------------------------------------
diff --git a/src/parquet/column/levels.cc b/src/parquet/column/levels.cc
index 6f87ad8..9b2d901 100644
--- a/src/parquet/column/levels.cc
+++ b/src/parquet/column/levels.cc
@@ -90,8 +90,7 @@ int LevelEncoder::Encode(int batch_size, const int16_t* levels) {
   return num_encoded;
 }
 
-LevelDecoder::LevelDecoder()
-    : num_values_remaining_(0) {}
+LevelDecoder::LevelDecoder() : num_values_remaining_(0) {}
 
 LevelDecoder::~LevelDecoder() {}
 

http://git-wip-us.apache.org/repos/asf/parquet-cpp/blob/f97042d9/src/parquet/column/properties.h
----------------------------------------------------------------------
diff --git a/src/parquet/column/properties.h b/src/parquet/column/properties.h
index 4296229..848cf59 100644
--- a/src/parquet/column/properties.h
+++ b/src/parquet/column/properties.h
@@ -26,6 +26,7 @@
 #include "parquet/schema/types.h"
 #include "parquet/util/input.h"
 #include "parquet/util/mem-allocator.h"
+#include "parquet/util/visibility.h"
 
 namespace parquet {
 
@@ -36,7 +37,7 @@ struct ParquetVersion {
 static int64_t DEFAULT_BUFFER_SIZE = 0;
 static bool DEFAULT_USE_BUFFERED_STREAM = false;
 
-class ReaderProperties {
+class PARQUET_EXPORT ReaderProperties {
  public:
   explicit ReaderProperties(MemoryAllocator* allocator = default_allocator())
       : allocator_(allocator) {
@@ -74,7 +75,7 @@ class ReaderProperties {
   bool buffered_stream_enabled_;
 };
 
-ReaderProperties default_reader_properties();
+ReaderProperties PARQUET_EXPORT default_reader_properties();
 
 static int64_t DEFAULT_PAGE_SIZE = 1024 * 1024;
 static int64_t DEFAULT_DICTIONARY_PAGE_SIZE = DEFAULT_PAGE_SIZE;
@@ -86,7 +87,7 @@ static constexpr Compression::type DEFAULT_COMPRESSION_TYPE = Compression::UNCOM
 
 using ColumnCodecs = std::unordered_map<std::string, Compression::type>;
 
-class WriterProperties {
+class PARQUET_EXPORT WriterProperties {
  public:
   class Builder {
    public:
@@ -234,7 +235,7 @@ class WriterProperties {
   ColumnCodecs codecs_;
 };
 
-std::shared_ptr<WriterProperties> default_writer_properties();
+std::shared_ptr<WriterProperties> PARQUET_EXPORT default_writer_properties();
 
 }  // namespace parquet
 

http://git-wip-us.apache.org/repos/asf/parquet-cpp/blob/f97042d9/src/parquet/column/reader.h
----------------------------------------------------------------------
diff --git a/src/parquet/column/reader.h b/src/parquet/column/reader.h
index 926a2fd..633f3a3 100644
--- a/src/parquet/column/reader.h
+++ b/src/parquet/column/reader.h
@@ -31,10 +31,11 @@
 #include "parquet/schema/descriptor.h"
 #include "parquet/types.h"
 #include "parquet/util/mem-allocator.h"
+#include "parquet/util/visibility.h"
 
 namespace parquet {
 
-class ColumnReader {
+class PARQUET_EXPORT ColumnReader {
  public:
   ColumnReader(const ColumnDescriptor*, std::unique_ptr<PageReader>,
       MemoryAllocator* allocator = default_allocator());
@@ -97,7 +98,7 @@ class ColumnReader {
 
 // API to read values from a single column. This is the main client facing API.
 template <typename DType>
-class TypedColumnReader : public ColumnReader {
+class PARQUET_EXPORT TypedColumnReader : public ColumnReader {
  public:
   typedef typename DType::c_type T;
 

http://git-wip-us.apache.org/repos/asf/parquet-cpp/blob/f97042d9/src/parquet/column/scanner.h
----------------------------------------------------------------------
diff --git a/src/parquet/column/scanner.h b/src/parquet/column/scanner.h
index 201b62d..bc5c5ce 100644
--- a/src/parquet/column/scanner.h
+++ b/src/parquet/column/scanner.h
@@ -30,12 +30,13 @@
 #include "parquet/schema/descriptor.h"
 #include "parquet/types.h"
 #include "parquet/util/mem-allocator.h"
+#include "parquet/util/visibility.h"
 
 namespace parquet {
 
 static constexpr int64_t DEFAULT_SCANNER_BATCH_SIZE = 128;
 
-class Scanner {
+class PARQUET_EXPORT Scanner {
  public:
   explicit Scanner(std::shared_ptr<ColumnReader> reader,
       int64_t batch_size = DEFAULT_SCANNER_BATCH_SIZE,
@@ -85,7 +86,7 @@ class Scanner {
 };
 
 template <typename DType>
-class TypedScanner : public Scanner {
+class PARQUET_EXPORT TypedScanner : public Scanner {
  public:
   typedef typename DType::c_type T;
 

http://git-wip-us.apache.org/repos/asf/parquet-cpp/blob/f97042d9/src/parquet/column/writer.h
----------------------------------------------------------------------
diff --git a/src/parquet/column/writer.h b/src/parquet/column/writer.h
index 93c66a4..48e2f52 100644
--- a/src/parquet/column/writer.h
+++ b/src/parquet/column/writer.h
@@ -26,10 +26,11 @@
 #include "parquet/types.h"
 #include "parquet/util/mem-allocator.h"
 #include "parquet/util/output.h"
+#include "parquet/util/visibility.h"
 
 namespace parquet {
 
-class ColumnWriter {
+class PARQUET_EXPORT ColumnWriter {
  public:
   ColumnWriter(const ColumnDescriptor*, std::unique_ptr<PageWriter>,
       int64_t expected_rows, MemoryAllocator* allocator = default_allocator());
@@ -99,7 +100,7 @@ class ColumnWriter {
 
 // API to write values to a single column. This is the main client facing API.
 template <typename DType>
-class TypedColumnWriter : public ColumnWriter {
+class PARQUET_EXPORT TypedColumnWriter : public ColumnWriter {
  public:
   typedef typename DType::c_type T;
 

http://git-wip-us.apache.org/repos/asf/parquet-cpp/blob/f97042d9/src/parquet/exception.h
----------------------------------------------------------------------
diff --git a/src/parquet/exception.h b/src/parquet/exception.h
index 03f2356..6e6589e 100644
--- a/src/parquet/exception.h
+++ b/src/parquet/exception.h
@@ -22,6 +22,8 @@
 #include <sstream>
 #include <string>
 
+#include "parquet/util/visibility.h"
+
 namespace parquet {
 
 class ParquetException : public std::exception {

http://git-wip-us.apache.org/repos/asf/parquet-cpp/blob/f97042d9/src/parquet/file/reader.h
----------------------------------------------------------------------
diff --git a/src/parquet/file/reader.h b/src/parquet/file/reader.h
index 4fc034d..8e0d26f 100644
--- a/src/parquet/file/reader.h
+++ b/src/parquet/file/reader.h
@@ -28,6 +28,7 @@
 #include "parquet/column/page.h"
 #include "parquet/column/properties.h"
 #include "parquet/schema/descriptor.h"
+#include "parquet/util/visibility.h"
 
 namespace parquet {
 
@@ -42,7 +43,7 @@ struct RowGroupStatistics {
   const std::string* max;
 };
 
-class RowGroupReader {
+class PARQUET_EXPORT RowGroupReader {
  public:
   // Forward declare the PIMPL
   struct Contents {
@@ -85,7 +86,7 @@ class RowGroupReader {
   MemoryAllocator* allocator_;
 };
 
-class ParquetFileReader {
+class PARQUET_EXPORT ParquetFileReader {
  public:
   // Forward declare the PIMPL
   struct Contents {

http://git-wip-us.apache.org/repos/asf/parquet-cpp/blob/f97042d9/src/parquet/file/writer.h
----------------------------------------------------------------------
diff --git a/src/parquet/file/writer.h b/src/parquet/file/writer.h
index 223c4bb..a5e6e99 100644
--- a/src/parquet/file/writer.h
+++ b/src/parquet/file/writer.h
@@ -25,6 +25,7 @@
 #include "parquet/schema/descriptor.h"
 #include "parquet/schema/types.h"
 #include "parquet/util/mem-allocator.h"
+#include "parquet/util/visibility.h"
 
 namespace parquet {
 
@@ -32,7 +33,7 @@ class ColumnWriter;
 class PageWriter;
 class OutputStream;
 
-class RowGroupWriter {
+class PARQUET_EXPORT RowGroupWriter {
  public:
   struct Contents {
     virtual int num_columns() const = 0;
@@ -81,7 +82,7 @@ class RowGroupWriter {
   MemoryAllocator* allocator_;
 };
 
-class ParquetFileWriter {
+class PARQUET_EXPORT ParquetFileWriter {
  public:
   struct Contents {
     virtual ~Contents() {}

http://git-wip-us.apache.org/repos/asf/parquet-cpp/blob/f97042d9/src/parquet/schema/descriptor.h
----------------------------------------------------------------------
diff --git a/src/parquet/schema/descriptor.h b/src/parquet/schema/descriptor.h
index eb6eac6..51f3503 100644
--- a/src/parquet/schema/descriptor.h
+++ b/src/parquet/schema/descriptor.h
@@ -26,6 +26,7 @@
 #include <vector>
 #include "parquet/schema/types.h"
 #include "parquet/types.h"
+#include "parquet/util/visibility.h"
 
 namespace parquet {
 
@@ -36,7 +37,7 @@ class SchemaDescriptor;
 // examine the node structure of a column's path to the root in the schema tree
 // to be able to reassemble the nested structure from the repetition and
 // definition levels.
-class ColumnDescriptor {
+class PARQUET_EXPORT ColumnDescriptor {
  public:
   ColumnDescriptor(const schema::NodePtr& node, int16_t max_definition_level,
       int16_t max_repetition_level, const SchemaDescriptor* schema_descr = nullptr);
@@ -85,7 +86,7 @@ class ColumnDescriptor {
 // repetition-definition level encoding of nested data
 //
 // TODO(wesm): this object can be recomputed from a Schema
-class SchemaDescriptor {
+class PARQUET_EXPORT SchemaDescriptor {
  public:
   SchemaDescriptor() {}
   ~SchemaDescriptor() {}

http://git-wip-us.apache.org/repos/asf/parquet-cpp/blob/f97042d9/src/parquet/schema/printer.h
----------------------------------------------------------------------
diff --git a/src/parquet/schema/printer.h b/src/parquet/schema/printer.h
index e3e2f32..c37ef90 100644
--- a/src/parquet/schema/printer.h
+++ b/src/parquet/schema/printer.h
@@ -22,13 +22,16 @@
 
 #include <ostream>
 
+#include "parquet/util/visibility.h"
+
 namespace parquet {
 
 namespace schema {
 
 class Node;
 
-void PrintSchema(const Node* schema, std::ostream& stream, int indent_width = 2);
+void PARQUET_EXPORT PrintSchema(
+    const Node* schema, std::ostream& stream, int indent_width = 2);
 
 }  // namespace schema
 

http://git-wip-us.apache.org/repos/asf/parquet-cpp/blob/f97042d9/src/parquet/schema/types.h
----------------------------------------------------------------------
diff --git a/src/parquet/schema/types.h b/src/parquet/schema/types.h
index cceb998..f315480 100644
--- a/src/parquet/schema/types.h
+++ b/src/parquet/schema/types.h
@@ -28,9 +28,9 @@
 
 #include "parquet/types.h"
 #include "parquet/util/macros.h"
+#include "parquet/util/visibility.h"
 
 namespace parquet {
-
 namespace schema {
 
 // List encodings: using the terminology from Impala to define different styles
@@ -75,7 +75,7 @@ struct DecimalMetadata {
   int32_t precision;
 };
 
-class ColumnPath {
+class PARQUET_EXPORT ColumnPath {
  public:
   ColumnPath() : path_() {}
   explicit ColumnPath(const std::vector<std::string>& path) : path_(path) {}
@@ -95,7 +95,7 @@ class GroupNode;
 
 // Base class for logical schema types. A type has a name, repetition level,
 // and optionally a logical type (ConvertedType in Parquet metadata parlance)
-class Node {
+class PARQUET_EXPORT Node {
  public:
   enum type { PRIMITIVE, GROUP };
 
@@ -178,7 +178,7 @@ typedef std::vector<NodePtr> NodeVector;
 // the other type metadata (name, repetition level, logical type), also has the
 // physical storage type and their type-specific metadata (byte width, decimal
 // parameters)
-class PrimitiveNode : public Node {
+class PARQUET_EXPORT PrimitiveNode : public Node {
  public:
   // FromParquet accepts an opaque void* to avoid exporting
   // parquet::SchemaElement into the public API
@@ -229,7 +229,7 @@ class PrimitiveNode : public Node {
   FRIEND_TEST(TestPrimitiveNode, FromParquet);
 };
 
-class GroupNode : public Node {
+class PARQUET_EXPORT GroupNode : public Node {
  public:
   // Like PrimitiveNode, GroupNode::FromParquet accepts an opaque void* to avoid exporting
   // parquet::SchemaElement into the public API

http://git-wip-us.apache.org/repos/asf/parquet-cpp/blob/f97042d9/src/parquet/symbols.map
----------------------------------------------------------------------
diff --git a/src/parquet/symbols.map b/src/parquet/symbols.map
new file mode 100644
index 0000000..d37b0dd
--- /dev/null
+++ b/src/parquet/symbols.map
@@ -0,0 +1,34 @@
+{
+  # Symbols marked as 'local' are not exported by the DSO and thus may not
+  # be used by client applications.
+  local:
+    # zlib
+    adler32*;
+    crc32*;
+    get_crc_table;
+    inflate*;
+    zError;
+    zlib*;
+
+	# these symbols seem to not universally be found in all libz.a
+	deflate*;
+	zc*;
+	_tr_*;
+
+    # devtoolset / static-libstdc++ symbols
+    __cxa_*;
+
+    extern "C++" {
+      # snappy
+	  snappy::*;
+
+	  # thrift
+	  apache::thrift::*;
+
+      # devtoolset or -static-libstdc++ - the Red Hat devtoolset statically
+      # links c++11 symbols into binaries so that the result may be executed on
+      # a system with an older libstdc++ which doesn't include the necessary
+      # c++11 symbols.
+      std::*;
+    };
+};

http://git-wip-us.apache.org/repos/asf/parquet-cpp/blob/f97042d9/src/parquet/types.h
----------------------------------------------------------------------
diff --git a/src/parquet/types.h b/src/parquet/types.h
index 049e75b..c952b06 100644
--- a/src/parquet/types.h
+++ b/src/parquet/types.h
@@ -25,6 +25,7 @@
 #include <string>
 
 #include "parquet/util/compiler-util.h"
+#include "parquet/util/visibility.h"
 
 namespace parquet {
 

http://git-wip-us.apache.org/repos/asf/parquet-cpp/blob/f97042d9/src/parquet/util/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/parquet/util/CMakeLists.txt b/src/parquet/util/CMakeLists.txt
index a09291b..52c4811 100644
--- a/src/parquet/util/CMakeLists.txt
+++ b/src/parquet/util/CMakeLists.txt
@@ -34,6 +34,7 @@ install(FILES
   rle-encoding.h
   stopwatch.h
   sse-util.h
+  visibility.h
   DESTINATION include/parquet/util)
 
 if(PARQUET_BUILD_TESTS)

http://git-wip-us.apache.org/repos/asf/parquet-cpp/blob/f97042d9/src/parquet/util/buffer.h
----------------------------------------------------------------------
diff --git a/src/parquet/util/buffer.h b/src/parquet/util/buffer.h
index c0f263f..de64265 100644
--- a/src/parquet/util/buffer.h
+++ b/src/parquet/util/buffer.h
@@ -26,6 +26,7 @@
 
 #include "parquet/util/macros.h"
 #include "parquet/util/mem-allocator.h"
+#include "parquet/util/visibility.h"
 
 namespace parquet {
 
@@ -34,7 +35,7 @@ namespace parquet {
 
 // Immutable API for a chunk of bytes which may or may not be owned by the
 // class instance
-class Buffer : public std::enable_shared_from_this<Buffer> {
+class PARQUET_EXPORT Buffer : public std::enable_shared_from_this<Buffer> {
  public:
   Buffer(const uint8_t* data, int64_t size) : data_(data), size_(size) {}
 
@@ -78,7 +79,7 @@ class Buffer : public std::enable_shared_from_this<Buffer> {
 };
 
 // A Buffer whose contents can be mutated. May or may not own its data.
-class MutableBuffer : public Buffer {
+class PARQUET_EXPORT MutableBuffer : public Buffer {
  public:
   MutableBuffer(uint8_t* data, int64_t size) : Buffer(data, size) {
     mutable_data_ = data;
@@ -95,7 +96,7 @@ class MutableBuffer : public Buffer {
   uint8_t* mutable_data_;
 };
 
-class ResizableBuffer : public MutableBuffer {
+class PARQUET_EXPORT ResizableBuffer : public MutableBuffer {
  public:
   virtual void Resize(int64_t new_size) = 0;
 
@@ -108,7 +109,7 @@ class ResizableBuffer : public MutableBuffer {
 // A ResizableBuffer whose memory is owned by the class instance. For example,
 // for reading data out of files that you want to deallocate when this class is
 // garbage-collected
-class OwnedMutableBuffer : public ResizableBuffer {
+class PARQUET_EXPORT OwnedMutableBuffer : public ResizableBuffer {
  public:
   explicit OwnedMutableBuffer(
       int64_t size = 0, MemoryAllocator* allocator = default_allocator());

http://git-wip-us.apache.org/repos/asf/parquet-cpp/blob/f97042d9/src/parquet/util/input.h
----------------------------------------------------------------------
diff --git a/src/parquet/util/input.h b/src/parquet/util/input.h
index 85b78cd..d6d6f34 100644
--- a/src/parquet/util/input.h
+++ b/src/parquet/util/input.h
@@ -18,14 +18,15 @@
 #ifndef PARQUET_UTIL_INPUT_H
 #define PARQUET_UTIL_INPUT_H
 
-#include <parquet/util/mem-allocator.h>
-
 #include <cstdint>
 #include <cstdio>
 #include <memory>
 #include <string>
 #include <vector>
 
+#include "parquet/util/mem-allocator.h"
+#include "parquet/util/visibility.h"
+
 namespace parquet {
 
 class Buffer;
@@ -35,7 +36,7 @@ class OwnedMutableBuffer;
 // Random access input (e.g. file-like)
 
 // Random
-class RandomAccessSource {
+class PARQUET_EXPORT RandomAccessSource {
  public:
   virtual ~RandomAccessSource() {}
 
@@ -54,7 +55,7 @@ class RandomAccessSource {
   int64_t size_;
 };
 
-class LocalFileSource : public RandomAccessSource {
+class PARQUET_EXPORT LocalFileSource : public RandomAccessSource {
  public:
   explicit LocalFileSource(MemoryAllocator* allocator = default_allocator())
       : file_(nullptr), is_open_(false), allocator_(allocator) {}
@@ -88,7 +89,7 @@ class LocalFileSource : public RandomAccessSource {
   MemoryAllocator* allocator_;
 };
 
-class MemoryMapSource : public LocalFileSource {
+class PARQUET_EXPORT MemoryMapSource : public LocalFileSource {
  public:
   explicit MemoryMapSource(MemoryAllocator* allocator = default_allocator())
       : LocalFileSource(allocator), data_(nullptr), pos_(0) {}
@@ -118,7 +119,7 @@ class MemoryMapSource : public LocalFileSource {
 // ----------------------------------------------------------------------
 // A file-like object that reads from virtual address space
 
-class BufferReader : public RandomAccessSource {
+class PARQUET_EXPORT BufferReader : public RandomAccessSource {
  public:
   explicit BufferReader(const std::shared_ptr<Buffer>& buffer);
   virtual void Close() {}

http://git-wip-us.apache.org/repos/asf/parquet-cpp/blob/f97042d9/src/parquet/util/mem-allocator.h
----------------------------------------------------------------------
diff --git a/src/parquet/util/mem-allocator.h b/src/parquet/util/mem-allocator.h
index 3f387c3..b20d9f9 100644
--- a/src/parquet/util/mem-allocator.h
+++ b/src/parquet/util/mem-allocator.h
@@ -20,9 +20,11 @@
 
 #include <cstdint>
 
+#include "parquet/util/visibility.h"
+
 namespace parquet {
 
-class MemoryAllocator {
+class PARQUET_EXPORT MemoryAllocator {
  public:
   virtual ~MemoryAllocator();
 
@@ -31,9 +33,9 @@ class MemoryAllocator {
   virtual void Free(uint8_t* p, int64_t size) = 0;
 };
 
-MemoryAllocator* default_allocator();
+PARQUET_EXPORT MemoryAllocator* default_allocator();
 
-class TrackingAllocator : public MemoryAllocator {
+class PARQUET_EXPORT TrackingAllocator : public MemoryAllocator {
  public:
   TrackingAllocator() : total_memory_(0), max_memory_(0) {}
   virtual ~TrackingAllocator();

http://git-wip-us.apache.org/repos/asf/parquet-cpp/blob/f97042d9/src/parquet/util/output.h
----------------------------------------------------------------------
diff --git a/src/parquet/util/output.h b/src/parquet/util/output.h
index a7cb773..9b2c2d3 100644
--- a/src/parquet/util/output.h
+++ b/src/parquet/util/output.h
@@ -24,6 +24,7 @@
 
 #include "parquet/util/macros.h"
 #include "parquet/util/mem-allocator.h"
+#include "parquet/util/visibility.h"
 
 namespace parquet {
 
@@ -34,7 +35,7 @@ class ResizableBuffer;
 // Output stream classes
 
 // Abstract output stream
-class OutputStream {
+class PARQUET_EXPORT OutputStream {
  public:
   virtual ~OutputStream();
 
@@ -51,7 +52,7 @@ class OutputStream {
 static constexpr int64_t IN_MEMORY_DEFAULT_CAPACITY = 1024;
 
 // An output stream that is an in-memory
-class InMemoryOutputStream : public OutputStream {
+class PARQUET_EXPORT InMemoryOutputStream : public OutputStream {
  public:
   explicit InMemoryOutputStream(int64_t initial_capacity = IN_MEMORY_DEFAULT_CAPACITY,
       MemoryAllocator* allocator = default_allocator());
@@ -79,7 +80,7 @@ class InMemoryOutputStream : public OutputStream {
   DISALLOW_COPY_AND_ASSIGN(InMemoryOutputStream);
 };
 
-class LocalFileOutputStream : public OutputStream {
+class PARQUET_EXPORT LocalFileOutputStream : public OutputStream {
  public:
   explicit LocalFileOutputStream(const std::string& path);
 

http://git-wip-us.apache.org/repos/asf/parquet-cpp/blob/f97042d9/src/parquet/util/visibility.h
----------------------------------------------------------------------
diff --git a/src/parquet/util/visibility.h b/src/parquet/util/visibility.h
new file mode 100644
index 0000000..64eef90
--- /dev/null
+++ b/src/parquet/util/visibility.h
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#ifndef PARQUET_UTIL_VISIBILITY_H
+#define PARQUET_UTIL_VISIBILITY_H
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+#define PARQUET_EXPORT __declspec(dllexport)
+#else  // Not Windows
+#ifndef PARQUET_EXPORT
+#define PARQUET_EXPORT __attribute__((visibility("default")))
+#endif
+#ifndef PARQUET_NO_EXPORT
+#define PARQUET_NO_EXPORT __attribute__((visibility("hidden")))
+#endif
+#endif  // Non-Windows
+
+#endif  // PARQUET_UTIL_VISIBILITY_H