summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNobuaki Sukegawa <nsuke@apache.org>2016-09-10 14:02:19 +0900
committerNobuaki Sukegawa <nsuke@apache.org>2016-09-26 01:42:01 +0900
commit11da87e6f30c237869a09e28ab44fe4a59db270e (patch)
tree4c81e09a6c5647cf8b4216379c30ec8ec2cb5517
parent1e3cf9b9fdcf9a7b7ffc18a2e6148465b154e66b (diff)
downloadthrift-11da87e6f30c237869a09e28ab44fe4a59db270e.tar.gz
THRIFT-2835 Add possibility to distribute generators separately from thrift core, and load them dynamically
Client: Compiler Patch: Nobuaki Sukegawa, rebased by dtmuller Also fixed by dtmuller: * Add plugin namespace for erlang language binding * Fix unit test test_const_value * Don't clear type cache with every t_program conversion * Type "wb" may not be supported by popen on non-Windows platforms * Fix constness of AST type signatures
-rw-r--r--.gitignore13
-rw-r--r--CMakeLists.txt3
-rwxr-xr-xMakefile.am8
-rw-r--r--build/cmake/DefineOptions.cmake32
-rw-r--r--build/cmake/ThriftMacros.cmake19
-rw-r--r--compiler/cpp/CMakeLists.txt91
-rw-r--r--compiler/cpp/Makefile.am65
-rw-r--r--compiler/cpp/compiler.vcxproj6
-rw-r--r--compiler/cpp/src/Makefile.am87
-rw-r--r--compiler/cpp/src/common.cc69
-rw-r--r--compiler/cpp/src/common.h43
-rw-r--r--compiler/cpp/src/generate/t_generator.cc19
-rw-r--r--compiler/cpp/src/generate/t_generator.h6
-rw-r--r--compiler/cpp/src/generate/t_generator_registry.h4
-rw-r--r--compiler/cpp/src/generate/t_oop_generator.h2
-rw-r--r--compiler/cpp/src/generate/t_rb_generator.cc10
-rw-r--r--compiler/cpp/src/globals.h15
-rw-r--r--compiler/cpp/src/logging.cc77
-rw-r--r--compiler/cpp/src/logging.h4
-rw-r--r--compiler/cpp/src/main.cc74
-rw-r--r--compiler/cpp/src/parse/parse.cc8
-rw-r--r--compiler/cpp/src/parse/t_const_value.h9
-rw-r--r--compiler/cpp/src/parse/t_container.h4
-rw-r--r--compiler/cpp/src/parse/t_doc.h1
-rw-r--r--compiler/cpp/src/parse/t_enum.h6
-rw-r--r--compiler/cpp/src/parse/t_enum_value.h1
-rw-r--r--compiler/cpp/src/parse/t_field.h8
-rw-r--r--compiler/cpp/src/parse/t_program.h8
-rw-r--r--compiler/cpp/src/parse/t_scope.h9
-rw-r--r--compiler/cpp/src/parse/t_service.h2
-rw-r--r--compiler/cpp/src/parse/t_struct.h12
-rw-r--r--compiler/cpp/src/parse/t_type.h1
-rw-r--r--compiler/cpp/src/plugin/Makefile.am47
-rw-r--r--compiler/cpp/src/plugin/plugin.cc503
-rw-r--r--compiler/cpp/src/plugin/plugin.h44
-rw-r--r--compiler/cpp/src/plugin/plugin.thrift202
-rw-r--r--compiler/cpp/src/plugin/plugin_output.cc410
-rw-r--r--compiler/cpp/src/plugin/plugin_output.h38
-rw-r--r--compiler/cpp/src/plugin/type_util.h94
-rw-r--r--compiler/cpp/src/thriftl.ll1
-rw-r--r--compiler/cpp/src/thrifty.yy1
-rw-r--r--compiler/cpp/src/version.h.in (renamed from compiler/cpp/version.h.in)0
-rw-r--r--compiler/cpp/test/CMakeLists.txt77
-rw-r--r--compiler/cpp/test/Makefile.am51
-rw-r--r--compiler/cpp/test/cpp_plugin_test.cmake45
-rwxr-xr-xcompiler/cpp/test/cpp_plugin_test.sh27
-rw-r--r--compiler/cpp/test/plugin/conversion_test.cc496
-rw-r--r--compiler/cpp/test/plugin/cpp_plugin.cc43
-rwxr-xr-xconfigure.ac22
-rwxr-xr-xdebian/rules6
-rw-r--r--lib/Makefile.am3
-rw-r--r--lib/c_glib/test/CMakeLists.txt8
-rwxr-xr-xlib/cpp/CMakeLists.txt7
-rwxr-xr-xlib/cpp/Makefile.am4
-rw-r--r--lib/cpp/src/thrift/protocol/TJSONProtocol.cpp2
-rw-r--r--lib/cpp/src/thrift/protocol/TProtocol.h5
-rw-r--r--lib/cpp/src/thrift/windows/GetTimeOfDay.cpp2
-rw-r--r--lib/cpp/src/thrift/windows/GetTimeOfDay.h1
-rw-r--r--lib/cpp/src/thrift/windows/config.h1
-rw-r--r--lib/cpp/test/CMakeLists.txt7
-rwxr-xr-xlib/cpp/test/Makefile.am2
-rwxr-xr-xtest/cpp/CMakeLists.txt2
-rw-r--r--tutorial/cpp/CMakeLists.txt3
63 files changed, 2701 insertions, 169 deletions
diff --git a/.gitignore b/.gitignore
index 286d7394f..94e851967 100644
--- a/.gitignore
+++ b/.gitignore
@@ -47,9 +47,18 @@ erl_crash.dump
/aclocal/lt*.m4
/autoscan.log
/autoscan-*.log
+/compiler/cpp/test/plugin/t_cpp_generator.cc
+/compiler/cpp/src/plugin/plugin_constants.cpp
+/compiler/cpp/src/plugin/plugin_constants.h
+/compiler/cpp/src/plugin/plugin_types.cpp
+/compiler/cpp/src/plugin/plugin_types.h
+/compiler/cpp/test/*test
+/compiler/cpp/test/thrift-gen-*
+/compiler/cpp/src/thrift-bootstrap
+/compiler/cpp/src/plugin/gen.stamp
/compiler/cpp/Debug
/compiler/cpp/Release
-/compiler/cpp/libparse.a
+/compiler/cpp/src/libparse.a
/compiler/cpp/src/thriftl.cc
/compiler/cpp/src/thrifty.cc
/compiler/cpp/src/thrifty.hh
@@ -60,7 +69,7 @@ erl_crash.dump
/compiler/cpp/lex.yythriftl.cc
/compiler/cpp/thrifty.h
/compiler/cpp/thrifty.hh
-/compiler/cpp/version.h
+/compiler/cpp/src/version.h
/config.*
/configure
/configure.lineno
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 37e89766f..93ed8d2ac 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -73,6 +73,9 @@ if(BUILD_COMPILER)
set(THRIFT_COMPILER $<TARGET_FILE:thrift-compiler>)
endif()
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/compiler/cpp)
+elseif(EXISTS ${THRIFT_COMPILER})
+ add_executable(thrift-compiler IMPORTED)
+ set_property(TARGET thrift-compiler PROPERTY IMPORTED_LOCATION ${THRIFT_COMPILER})
endif()
if(BUILD_CPP)
diff --git a/Makefile.am b/Makefile.am
index 38dd8c9d6..ed58265ac 100755
--- a/Makefile.am
+++ b/Makefile.am
@@ -19,7 +19,15 @@
ACLOCAL_AMFLAGS = -I ./aclocal
+if WITH_PLUGIN
+# To enable bootstrap, build order is lib/cpp -> compiler -> others
+SUBDIRS = lib/cpp compiler/cpp lib
+if WITH_TESTS
+SUBDIRS += lib/cpp/test
+endif
+else
SUBDIRS = compiler/cpp lib
+endif
if WITH_TESTS
SUBDIRS += test
diff --git a/build/cmake/DefineOptions.cmake b/build/cmake/DefineOptions.cmake
index 6dd59e0ff..171c9fefa 100644
--- a/build/cmake/DefineOptions.cmake
+++ b/build/cmake/DefineOptions.cmake
@@ -40,6 +40,13 @@ option(BUILD_LIBRARIES "Build Thrift libraries" ON)
# and enables the library if all are found. This means the default is to build as
# much as possible but leaving out libraries if their dependencies are not met.
+CMAKE_DEPENDENT_OPTION(WITH_BOOST_STATIC "Build with Boost static link library" OFF "NOT MSVC" ON)
+set(Boost_USE_STATIC_LIBS ${WITH_BOOST_STATIC})
+if (NOT WITH_BOOST_STATIC)
+ add_definitions(-DBOOST_ALL_DYN_LINK)
+ add_definitions(-DBOOST_TEST_DYN_LINK)
+endif()
+
# C++
option(WITH_CPP "Build C++ Thrift library" ON)
if(WITH_CPP)
@@ -77,6 +84,8 @@ if(WITH_CPP)
endif()
CMAKE_DEPENDENT_OPTION(BUILD_CPP "Build C++ library" ON
"BUILD_LIBRARIES;WITH_CPP;Boost_FOUND" OFF)
+CMAKE_DEPENDENT_OPTION(WITH_PLUGIN "Build compiler plugin support" ON
+ "BUILD_COMPILER;BUILD_CPP" OFF)
# C GLib
option(WITH_C_GLIB "Build C (GLib) Thrift library" ON)
@@ -86,6 +95,21 @@ endif()
CMAKE_DEPENDENT_OPTION(BUILD_C_GLIB "Build C (GLib) library" ON
"BUILD_LIBRARIES;WITH_C_GLIB;GLIB_FOUND" OFF)
+if(BUILD_CPP)
+ set(boost_components)
+ if(WITH_BOOSTTHREADS OR BUILD_TESTING)
+ list(APPEND boost_components system thread)
+ endif()
+ if(BUILD_TESTING)
+ list(APPEND boost_components unit_test_framework filesystem chrono program_options)
+ endif()
+ if(boost_components)
+ find_package(Boost 1.53 REQUIRED COMPONENTS ${boost_components})
+ endif()
+elseif(BUILD_C_GLIB AND BUILD_TESTING)
+ find_package(Boost 1.53 REQUIRED)
+endif()
+
# Java
option(WITH_JAVA "Build Java Thrift library" ON)
if(ANDROID)
@@ -120,8 +144,6 @@ if (NOT WITH_SHARED_LIB AND NOT WITH_STATIC_LIB)
message(FATAL_ERROR "Cannot build with both shared and static outputs disabled!")
endif()
-option(WITH_DYN_LINK_TEST "Build with Boost dynamic link test library" OFF)
-
#NOTE: C++ compiler options are defined in the lib/cpp/CMakeLists.txt
# Visual Studio only options
@@ -141,6 +163,7 @@ message(STATUS "Thrift version: ${thrift_VERSION}
message(STATUS "Thrift package version: ${PACKAGE_VERSION}")
message(STATUS "Build configuration Summary")
message(STATUS " Build Thrift compiler: ${BUILD_COMPILER}")
+message(STATUS " Build compiler plugin support: ${WITH_PLUGIN}")
message(STATUS " Build with unit tests: ${BUILD_TESTING}")
MESSAGE_DEP(HAVE_COMPILER "Disabled because BUILD_THRIFT=OFF and no valid THRIFT_COMPILER is given")
message(STATUS " Build examples: ${BUILD_EXAMPLES}")
@@ -178,6 +201,9 @@ message(STATUS " Build with Qt5 support: ${WITH_QT5}")
message(STATUS " Build with OpenSSL support: ${WITH_OPENSSL}")
message(STATUS " Build with Boost thread support: ${WITH_BOOSTTHREADS}")
message(STATUS " Build with C++ std::thread support: ${WITH_STDTHREADS}")
-message(STATUS " Build with Boost dynamic link test library: ${WITH_DYN_LINK_TEST}")
+message(STATUS " Build with Boost static link library: ${WITH_BOOST_STATIC}")
+if(MSVC)
+ message(STATUS " - Enabled for Visual C++")
+endif()
message(STATUS "----------------------------------------------------------")
endmacro(PRINT_CONFIG_SUMMARY)
diff --git a/build/cmake/ThriftMacros.cmake b/build/cmake/ThriftMacros.cmake
index 265659814..f837f9482 100644
--- a/build/cmake/ThriftMacros.cmake
+++ b/build/cmake/ThriftMacros.cmake
@@ -25,7 +25,6 @@ macro(ADD_LIBRARY_THRIFT name)
if(WITH_SHARED_LIB)
add_library(${name} SHARED ${ARGN})
- #target_link_libraries(${name} ${SYSLIBS})
set_target_properties(${name} PROPERTIES
OUTPUT_NAME ${name}
VERSION ${thrift_VERSION}
@@ -40,7 +39,6 @@ endif()
if(WITH_STATIC_LIB)
add_library(${name}_static STATIC ${ARGN})
- #target_link_libraries(${name}_static ${SYSLIBS})
set_target_properties(${name}_static PROPERTIES
OUTPUT_NAME ${name}${STATIC_POSTFIX}
VERSION ${thrift_VERSION}
@@ -55,6 +53,19 @@ endif()
endmacro(ADD_LIBRARY_THRIFT)
+macro(TARGET_INCLUDE_DIRECTORIES_THRIFT name)
+
+if(WITH_SHARED_LIB)
+ target_include_directories(${name} ${ARGN})
+endif()
+
+if(WITH_STATIC_LIB)
+ target_include_directories(${name}_static ${ARGN})
+endif()
+
+endmacro(TARGET_INCLUDE_DIRECTORIES_THRIFT)
+
+
macro(TARGET_LINK_LIBRARIES_THRIFT name)
if(WITH_SHARED_LIB)
@@ -84,11 +95,11 @@ endmacro(LINK_AGAINST_THRIFT_LIBRARY)
macro(TARGET_LINK_LIBRARIES_THRIFT_AGAINST_THRIFT_LIBRARY target libname)
if(WITH_SHARED_LIB)
- target_link_libraries(${target} ${libname})
+ target_link_libraries(${target} ${ARGN} ${libname})
endif()
if(WITH_STATIC_LIB)
- target_link_libraries(${target}_static ${libname}_static)
+ target_link_libraries(${target}_static ${ARGN} ${libname}_static)
endif()
endmacro(TARGET_LINK_LIBRARIES_THRIFT_AGAINST_THRIFT_LIBRARY)
diff --git a/compiler/cpp/CMakeLists.txt b/compiler/cpp/CMakeLists.txt
index b7ed6ea08..48cadbc1d 100644
--- a/compiler/cpp/CMakeLists.txt
+++ b/compiler/cpp/CMakeLists.txt
@@ -21,7 +21,7 @@
if(MSVC)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/windows/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h)
else()
- configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h)
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h)
endif()
find_package(FLEX REQUIRED)
@@ -47,39 +47,17 @@ set(libparse_SOURCES
add_library(libparse STATIC ${libparse_SOURCES})
# Create the thrift compiler
-set( thrift_SOURCES
- src/main.cc
+set(compiler_core
+ src/common.cc
src/generate/t_generator.cc
- src/generate/t_generator_registry.h
- src/globals.h
- src/main.h
- src/platform.h
- src/audit/t_audit.cpp
- src/parse/t_doc.h
- src/parse/t_type.h
- src/parse/t_base_type.h
- src/parse/t_enum.h
- src/parse/t_enum_value.h
- src/parse/t_typedef.h
src/parse/t_typedef.cc
- src/parse/t_container.h
- src/parse/t_list.h
- src/parse/t_set.h
- src/parse/t_map.h
- src/parse/t_struct.h
- src/parse/t_field.h
- src/parse/t_service.h
- src/parse/t_function.h
- src/parse/t_program.h
- src/parse/t_scope.h
- src/parse/t_const.h
- src/parse/t_const_value.h
src/parse/parse.cc
- src/generate/t_generator.h
- src/generate/t_oop_generator.h
- src/generate/t_html_generator.h
- src/windows/config.h
- version.h
+ ${CMAKE_CURRENT_BINARY_DIR}/version.h
+)
+
+set(thrift-compiler_SOURCES
+ src/main.cc
+ src/audit/t_audit.cpp
)
# This macro adds an option THRIFT_COMPILER_${NAME}
@@ -89,7 +67,7 @@ macro(THRIFT_ADD_COMPILER name description initial)
set(src "src/generate/t_${name}_generator.cc")
option(${enabler} ${description} ${initial})
if(${enabler})
- list(APPEND thrift_SOURCES ${src})
+ list(APPEND thrift-compiler_SOURCES ${src})
endif()
endmacro()
@@ -127,9 +105,56 @@ THRIFT_ADD_COMPILER(xml "Enable compiler for XML" ON)
# we also add the current binary directory for generated files
include_directories(${CMAKE_CURRENT_BINARY_DIR} src)
-add_executable(thrift-compiler ${thrift_SOURCES})
+if(NOT ${WITH_PLUGIN})
+ list(APPEND thrift-compiler_SOURCES ${compiler_core})
+endif()
+add_executable(thrift-compiler ${thrift-compiler_SOURCES})
+
+if(${WITH_PLUGIN})
+ add_executable(thrift-bootstrap ${compiler_core}
+ src/main.cc
+ src/audit/t_audit.cpp
+ src/generate/t_cpp_generator.cc
+ )
+ target_link_libraries(thrift-bootstrap libparse)
+
+ set(PLUGIN_GEN_SOURCES
+ ${CMAKE_CURRENT_BINARY_DIR}/plugin/plugin_types.h
+ ${CMAKE_CURRENT_BINARY_DIR}/plugin/plugin_types.cpp
+ ${CMAKE_CURRENT_BINARY_DIR}/plugin/plugin_constants.h
+ ${CMAKE_CURRENT_BINARY_DIR}/plugin/plugin_constants.cpp
+ )
+
+ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/plugin)
+ add_custom_command(OUTPUT ${PLUGIN_GEN_SOURCES}
+ DEPENDS thrift-bootstrap src/plugin/plugin.thrift
+ COMMAND thrift-bootstrap -gen cpp
+ -out ${CMAKE_CURRENT_BINARY_DIR}/plugin
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/plugin/plugin.thrift
+ )
+
+ include_directories(../../lib/cpp/src)
+
+ include(ThriftMacros)
+ ADD_LIBRARY_THRIFT(thriftc
+ ${compiler_core}
+ ${PLUGIN_GEN_SOURCES}
+ src/logging.cc
+ src/plugin/plugin_output.cc
+ src/plugin/plugin.cc
+ )
+ TARGET_INCLUDE_DIRECTORIES_THRIFT(thriftc PUBLIC ${Boost_INCLUDE_DIRS})
+ TARGET_LINK_LIBRARIES_THRIFT_AGAINST_THRIFT_LIBRARY(thriftc thrift PUBLIC)
+ target_compile_definitions(thrift-compiler PUBLIC THRIFT_ENABLE_PLUGIN)
+ LINK_AGAINST_THRIFT_LIBRARY(thrift-compiler thriftc)
+endif()
+
set_target_properties(thrift-compiler PROPERTIES OUTPUT_NAME thrift)
target_link_libraries(thrift-compiler libparse)
install(TARGETS thrift-compiler DESTINATION "${BIN_INSTALL_DIR}")
+
+if(BUILD_TESTING)
+ add_subdirectory(test)
+endif()
diff --git a/compiler/cpp/Makefile.am b/compiler/cpp/Makefile.am
index 49ec26e3b..f7a717165 100644
--- a/compiler/cpp/Makefile.am
+++ b/compiler/cpp/Makefile.am
@@ -21,25 +21,34 @@
# Please see doc/old-thrift-license.txt in the Thrift distribution for
# details.
-AM_YFLAGS = -d
-LIBS =
-BUILT_SOURCES = src/thrifty.cc
+AUTOMAKE_OPTIONS = subdir-objects
-bin_PROGRAMS = thrift
+# Note on why we have src and src/plugin directories:
+# Since Automake supports only one set of BUILT_SOURCES per file and does not allow
+# SUBDIRS built before BUILT_SOURCES, we end up separate Makefile.am for each source
+# code generation, i.e. lex-yacc and Thrift, to achieve stable parallel make.
+
+SUBDIRS = src src/plugin .
+if WITH_TESTS
+SUBDIRS += test
+endif
-noinst_LIBRARIES = libparse.a
+bin_PROGRAMS = thrift
thrift_OBJDIR = obj
-thrift_SOURCES = src/main.cc \
+plugin_gen = src/plugin/plugin_types.h \
+ src/plugin/plugin_types.cpp \
+ src/plugin/plugin_constants.h \
+ src/plugin/plugin_constants.cpp
+
+compiler_core = src/common.h \
+ src/common.cc \
src/generate/t_generator.cc \
src/generate/t_generator_registry.h \
src/globals.h \
- src/main.h \
src/platform.h \
src/logging.h \
- src/audit/t_audit.cpp \
- src/audit/t_audit.h \
src/parse/t_doc.h \
src/parse/t_type.h \
src/parse/t_base_type.h \
@@ -66,6 +75,11 @@ thrift_SOURCES = src/main.cc \
src/windows/config.h \
src/windows/version.h
+thrift_SOURCES = src/main.h \
+ src/main.cc \
+ src/audit/t_audit.cpp \
+ src/audit/t_audit.h
+
# Specific client generator source
thrift_SOURCES += src/generate/t_c_glib_generator.cc \
src/generate/t_cpp_generator.cc \
@@ -98,13 +112,32 @@ thrift_SOURCES += src/generate/t_c_glib_generator.cc \
thrift_CPPFLAGS = -I$(srcdir)/src
thrift_CXXFLAGS = -Wall -Wextra -pedantic
-thrift_LDADD = @LEXLIB@ libparse.a
+thrift_LDADD = @LEXLIB@ src/libparse.a
+
+if !WITH_PLUGIN
+thrift_SOURCES += $(compiler_core)
+else
+
+lib_LTLIBRARIES = libthriftc.la
+
+thrift_CPPFLAGS += -DTHRIFT_ENABLE_PLUGIN=1
+thrift_LDADD += libthriftc.la
+
+nodist_libthriftc_la_SOURCES = $(plugin_gen)
+libthriftc_la_SOURCES = $(compiler_core) \
+ src/plugin/type_util.h \
+ src/plugin/plugin.h \
+ src/plugin/plugin.cc \
+ src/plugin/plugin_output.h \
+ src/plugin/plugin_output.cc \
+ src/plugin/plugin.thrift \
+ src/logging.cc
-libparse_a_CPPFLAGS = -I$(srcdir)/src
-libparse_a_CXXFLAGS = -Wall -Wno-sign-compare -Wno-unused
-libparse_a_SOURCES = src/thrifty.yy \
- src/thriftl.ll
+libthriftc_la_CPPFLAGS = -I$(srcdir)/src -Isrc -I$(top_builddir)/lib/cpp/src -DTHRIFT_ENABLE_PLUGIN=1
+libthriftc_la_CXXFLAGS = -Wall -Wextra -pedantic
+libthriftc_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la
+endif
WINDOWS_DIST = \
compiler.sln \
@@ -118,9 +151,9 @@ EXTRA_DIST = \
$(WINDOWS_DIST)
clean-local:
- $(RM) thriftl.cc thrifty.cc thrifty.h thrifty.hh version.h windows/version.h
+ $(RM) version.h windows/version.h $(plugin_gen)
-src/main.cc: version.h
+src/main.cc: src/version.h
style-local:
$(CPPSTYLE_CMD)
diff --git a/compiler/cpp/compiler.vcxproj b/compiler/cpp/compiler.vcxproj
index a2548d4ab..3dbe42c9b 100644
--- a/compiler/cpp/compiler.vcxproj
+++ b/compiler/cpp/compiler.vcxproj
@@ -20,6 +20,7 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\audit\t_audit.h" />
+ <ClInclude Include="src\common.h" />
<ClInclude Include="src\generate\t_generator.h" />
<ClInclude Include="src\generate\t_generator_registry.h" />
<ClInclude Include="src\generate\t_oop_generator.h" />
@@ -50,7 +51,8 @@
<ClInclude Include="src\windows\version.h" />
</ItemGroup>
<ItemGroup>
- <ClCompile Include="src\audit\t_audit.cpp" />
+ <ClCompile Include="src\audit\t_audit.cpp"/>
+ <ClCompile Include="src\common.cc" />
<ClCompile Include="src\generate\t_as3_generator.cc" />
<ClCompile Include="src\generate\t_cocoa_generator.cc" />
<ClCompile Include="src\generate\t_cpp_generator.cc" />
@@ -245,4 +247,4 @@ bison -y -o "src\thrifty.cc" --defines="src/thrifty.hh" src/thrifty.yy</Command>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project> \ No newline at end of file
+</Project>
diff --git a/compiler/cpp/src/Makefile.am b/compiler/cpp/src/Makefile.am
new file mode 100644
index 000000000..e2fae709d
--- /dev/null
+++ b/compiler/cpp/src/Makefile.am
@@ -0,0 +1,87 @@
+#
+# 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.
+#
+#
+# Contains some contributions under the Thrift Software License.
+# Please see doc/old-thrift-license.txt in the Thrift distribution for
+# details.
+
+AUTOMAKE_OPTIONS = subdir-objects
+
+AM_YFLAGS = -d
+
+BUILT_SOURCES = thrifty.cc
+
+noinst_LIBRARIES = libparse.a
+
+libparse_a_CPPFLAGS = -I$(srcdir)
+libparse_a_CXXFLAGS = -Wall -Wno-sign-compare -Wno-unused
+
+libparse_a_SOURCES = thrifty.yy \
+ thriftl.ll
+
+clean-local:
+ $(RM) thriftl.cc thrifty.cc thrifty.h thrifty.hh
+
+if WITH_PLUGIN
+noinst_PROGRAMS = thrift-bootstrap
+
+thrift_bootstrap_SOURCES = \
+ common.h \
+ common.cc \
+ audit/t_audit.h \
+ audit/t_audit.cpp \
+ generate/t_generator.cc \
+ generate/t_generator_registry.h \
+ globals.h \
+ platform.h \
+ logging.h \
+ parse/t_doc.h \
+ parse/t_type.h \
+ parse/t_base_type.h \
+ parse/t_enum.h \
+ parse/t_enum_value.h \
+ parse/t_typedef.h \
+ parse/t_typedef.cc \
+ parse/t_container.h \
+ parse/t_list.h \
+ parse/t_set.h \
+ parse/t_map.h \
+ parse/t_struct.h \
+ parse/t_field.h \
+ parse/t_service.h \
+ parse/t_function.h \
+ parse/t_program.h \
+ parse/t_scope.h \
+ parse/t_const.h \
+ parse/t_const_value.h \
+ parse/parse.cc \
+ generate/t_generator.h \
+ generate/t_oop_generator.h \
+ generate/t_html_generator.h \
+ windows/config.h \
+ windows/version.h \
+ generate/t_cpp_generator.cc \
+ main.h \
+ main.cc
+
+main.cc: version.h
+
+thrift_bootstrap_CXXFLAGS = -Wall -Wextra -pedantic
+thrift_bootstrap_LDADD = @LEXLIB@ libparse.a
+endif
diff --git a/compiler/cpp/src/common.cc b/compiler/cpp/src/common.cc
new file mode 100644
index 000000000..6e11bb241
--- /dev/null
+++ b/compiler/cpp/src/common.cc
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#include "common.h"
+#include "parse/t_base_type.h"
+
+t_type* g_type_void;
+t_type* g_type_string;
+t_type* g_type_binary;
+t_type* g_type_slist;
+t_type* g_type_bool;
+t_type* g_type_i8;
+t_type* g_type_i16;
+t_type* g_type_i32;
+t_type* g_type_i64;
+t_type* g_type_double;
+
+void initGlobals() {
+ g_type_void = new t_base_type("void", t_base_type::TYPE_VOID);
+ g_type_string = new t_base_type("string", t_base_type::TYPE_STRING);
+ g_type_binary = new t_base_type("string", t_base_type::TYPE_STRING);
+ ((t_base_type*)g_type_binary)->set_binary(true);
+ g_type_slist = new t_base_type("string", t_base_type::TYPE_STRING);
+ ((t_base_type*)g_type_slist)->set_string_list(true);
+ g_type_bool = new t_base_type("bool", t_base_type::TYPE_BOOL);
+ g_type_i8 = new t_base_type("i8", t_base_type::TYPE_I8);
+ g_type_i16 = new t_base_type("i16", t_base_type::TYPE_I16);
+ g_type_i32 = new t_base_type("i32", t_base_type::TYPE_I32);
+ g_type_i64 = new t_base_type("i64", t_base_type::TYPE_I64);
+ g_type_double = new t_base_type("double", t_base_type::TYPE_DOUBLE);
+}
+
+void clearGlobals() {
+ delete g_type_void;
+ delete g_type_string;
+ delete g_type_bool;
+ delete g_type_i8;
+ delete g_type_i16;
+ delete g_type_i32;
+ delete g_type_i64;
+ delete g_type_double;
+}
+
+/**
+ * Those are not really needed for plugins but causes link errors without
+ */
+
+/**
+ * The location of the last parsed doctext comment.
+ */
+int g_doctext_lineno;
+int g_program_doctext_lineno = 0;
+PROGDOCTEXT_STATUS g_program_doctext_status = INVALID;
diff --git a/compiler/cpp/src/common.h b/compiler/cpp/src/common.h
new file mode 100644
index 000000000..ab7c42327
--- /dev/null
+++ b/compiler/cpp/src/common.h
@@ -0,0 +1,43 @@
+/*
+ * 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 T_COMMON_H
+#define T_COMMON_H
+
+#include "parse/t_type.h"
+
+/**
+ * Global types for the parser to be able to reference
+ */
+
+extern t_type* g_type_void;
+extern t_type* g_type_string;
+extern t_type* g_type_binary;
+extern t_type* g_type_slist;
+extern t_type* g_type_bool;
+extern t_type* g_type_i8;
+extern t_type* g_type_i16;
+extern t_type* g_type_i32;
+extern t_type* g_type_i64;
+extern t_type* g_type_double;
+
+void initGlobals();
+void clearGlobals();
+
+#endif
diff --git a/compiler/cpp/src/generate/t_generator.cc b/compiler/cpp/src/generate/t_generator.cc
index e7760d7dc..7f5daf442 100644
--- a/compiler/cpp/src/generate/t_generator.cc
+++ b/compiler/cpp/src/generate/t_generator.cc
@@ -127,11 +127,12 @@ void t_generator_registry::register_generator(t_generator_factory* factory) {
the_map[factory->get_short_name()] = factory;
}
-t_generator* t_generator_registry::get_generator(t_program* program, const string& options) {
+void t_generator::parse_options(const string& options,
+ string& language,
+ map<string, string>& parsed_options) {
string::size_type colon = options.find(':');
- string language = options.substr(0, colon);
+ language = options.substr(0, colon);
- map<string, string> parsed_options;
if (colon != string::npos) {
string::size_type pos = colon + 1;
while (pos != string::npos && pos < options.size()) {
@@ -152,7 +153,12 @@ t_generator* t_generator_registry::get_generator(t_program* program, const strin
parsed_options[key] = value;
}
}
+}
+t_generator* t_generator_registry::get_generator(t_program* program,
+ const string& language,
+ const map<string, string>& parsed_options,
+ const std::string& options) {
gen_map_t& the_map = get_generator_map();
gen_map_t::iterator iter = the_map.find(language);
@@ -163,6 +169,13 @@ t_generator* t_generator_registry::get_generator(t_program* program, const strin
return iter->second->get_generator(program, parsed_options, options);
}
+t_generator* t_generator_registry::get_generator(t_program* program, const string& options) {
+ string language;
+ map<string, string> parsed_options;
+ t_generator::parse_options(options, language, parsed_options);
+ return get_generator(program, language, parsed_options, options);
+}
+
t_generator_registry::gen_map_t& t_generator_registry::get_generator_map() {
// http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12
static gen_map_t* the_map = new gen_map_t();
diff --git a/compiler/cpp/src/generate/t_generator.h b/compiler/cpp/src/generate/t_generator.h
index 4136ab66c..590efdbae 100644
--- a/compiler/cpp/src/generate/t_generator.h
+++ b/compiler/cpp/src/generate/t_generator.h
@@ -25,7 +25,7 @@
#include <fstream>
#include <sstream>
#include "parse/t_program.h"
-#include "globals.h"
+#include "common.h"
#include "t_generator_registry.h"
#include "version.h"
@@ -66,6 +66,9 @@ public:
const std::string& contents,
const std::string& comment_end);
+ static void parse_options(const std::string& options, std::string& language,
+ std::map<std::string, std::string>& parsed_options);
+
/**
* check whether sub-namespace declaraction is used by generator.
* e.g. allow
@@ -257,6 +260,7 @@ public:
/**
* Get the true type behind a series of typedefs.
*/
+ static const t_type* get_true_type(const t_type* type) { return type->get_true_type(); }
static t_type* get_true_type(t_type* type) { return type->get_true_type(); }
protected:
diff --git a/compiler/cpp/src/generate/t_generator_registry.h b/compiler/cpp/src/generate/t_generator_registry.h
index a85238592..1f02167bc 100644
--- a/compiler/cpp/src/generate/t_generator_registry.h
+++ b/compiler/cpp/src/generate/t_generator_registry.h
@@ -81,6 +81,10 @@ public:
static void register_generator(t_generator_factory* factory);
static t_generator* get_generator(t_program* program, const std::string& options);
+ static t_generator* get_generator(t_program* program,
+ const std::string& laugnage,
+ const std::map<std::string, std::string>& parsed_options,
+ const std::string& options);
typedef std::map<std::string, t_generator_factory*> gen_map_t;
static gen_map_t& get_generator_map();
diff --git a/compiler/cpp/src/generate/t_oop_generator.h b/compiler/cpp/src/generate/t_oop_generator.h
index 07c9d85a3..e5a469842 100644
--- a/compiler/cpp/src/generate/t_oop_generator.h
+++ b/compiler/cpp/src/generate/t_oop_generator.h
@@ -23,7 +23,7 @@
#include <string>
#include <iostream>
-#include "globals.h"
+#include "common.h"
#include "t_generator.h"
#include <algorithm>
diff --git a/compiler/cpp/src/generate/t_rb_generator.cc b/compiler/cpp/src/generate/t_rb_generator.cc
index 49bf7e184..abd3320f8 100644
--- a/compiler/cpp/src/generate/t_rb_generator.cc
+++ b/compiler/cpp/src/generate/t_rb_generator.cc
@@ -195,14 +195,14 @@ public:
std::string render_require_thrift();
std::string render_includes();
std::string declare_field(t_field* tfield);
- std::string type_name(t_type* ttype);
- std::string full_type_name(t_type* ttype);
+ std::string type_name(const t_type* ttype);
+ std::string full_type_name(const t_type* ttype);
std::string function_signature(t_function* tfunction, std::string prefix = "");
std::string argument_list(t_struct* tstruct);
std::string type_to_enum(t_type* ttype);
std::string rb_namespace_to_path_prefix(std::string rb_namespace);
- std::vector<std::string> ruby_modules(t_program* p) {
+ std::vector<std::string> ruby_modules(const t_program* p) {
std::string ns = p->get_namespace("rb");
std::vector<std::string> modules;
if (ns.empty()) {
@@ -1101,7 +1101,7 @@ string t_rb_generator::argument_list(t_struct* tstruct) {
return result;
}
-string t_rb_generator::type_name(t_type* ttype) {
+string t_rb_generator::type_name(const t_type* ttype) {
string prefix = "";
string name = ttype->get_name();
@@ -1112,7 +1112,7 @@ string t_rb_generator::type_name(t_type* ttype) {
return prefix + name;
}
-string t_rb_generator::full_type_name(t_type* ttype) {
+string t_rb_generator::full_type_name(const t_type* ttype) {
string prefix = "::";
vector<std::string> modules = ruby_modules(ttype->get_program());
for (vector<std::string>::iterator m_iter = modules.begin(); m_iter != modules.end(); ++m_iter) {
diff --git a/compiler/cpp/src/globals.h b/compiler/cpp/src/globals.h
index c5c039468..961c6ef8a 100644
--- a/compiler/cpp/src/globals.h
+++ b/compiler/cpp/src/globals.h
@@ -62,21 +62,6 @@ extern int g_strict;
extern t_program* g_program;
/**
- * Global types for the parser to be able to reference
- */
-
-extern t_type* g_type_void;
-extern t_type* g_type_string;
-extern t_type* g_type_binary;
-extern t_type* g_type_slist;
-extern t_type* g_type_bool;
-extern t_type* g_type_i8;
-extern t_type* g_type_i16;
-extern t_type* g_type_i32;
-extern t_type* g_type_i64;
-extern t_type* g_type_double;
-
-/**
* The scope that we are currently parsing into
*/
extern t_scope* g_scope;
diff --git a/compiler/cpp/src/logging.cc b/compiler/cpp/src/logging.cc
new file mode 100644
index 000000000..2daaaec10
--- /dev/null
+++ b/compiler/cpp/src/logging.cc
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+/**
+ * Logging functions copied from main.cc to avoid link errors for plugins
+ */
+
+#include "logging.h"
+#include "globals.h"
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+
+// TODO: make plugins accept log options from main compiler
+int g_debug = 0;
+int g_warn = 1;
+int g_verbose = 0;
+
+void pdebug(const char* fmt, ...) {
+ if (g_debug == 0) {
+ return;
+ }
+ va_list args;
+ // printf("[PARSE:%d] ", yylineno);
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+ printf("\n");
+}
+
+void pverbose(const char* fmt, ...) {
+ if (g_verbose == 0) {
+ return;
+ }
+ va_list args;
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+}
+
+void pwarning(int level, const char* fmt, ...) {
+ if (g_warn < level) {
+ return;
+ }
+ va_list args;
+ // printf("[WARNING:%s:%d] ", g_curpath.c_str(), yylineno);
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+ printf("\n");
+}
+
+void failure(const char* fmt, ...) {
+ va_list args;
+ // fprintf(stderr, "[FAILURE:%s:%d] ", g_curpath.c_str(), yylineno);
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ printf("\n");
+ exit(1);
+}
diff --git a/compiler/cpp/src/logging.h b/compiler/cpp/src/logging.h
index 3f1fce87d..ebefbf229 100644
--- a/compiler/cpp/src/logging.h
+++ b/compiler/cpp/src/logging.h
@@ -20,7 +20,9 @@
#ifndef T_LOGGING_H
#define T_LOGGING_H
-#include <string>
+extern int g_debug;
+extern int g_warn;
+extern int g_verbose;
/**
* Parse debugging output, used to print helpful info
diff --git a/compiler/cpp/src/main.cc b/compiler/cpp/src/main.cc
index 89dd9f97e..510d69f47 100644
--- a/compiler/cpp/src/main.cc
+++ b/compiler/cpp/src/main.cc
@@ -44,6 +44,7 @@
#endif
// Careful: must include globals first for extern definitions
+#include "common.h"
#include "globals.h"
#include "platform.h"
@@ -52,6 +53,9 @@
#include "parse/t_scope.h"
#include "generate/t_generator.h"
#include "audit/t_audit.h"
+#ifdef THRIFT_ENABLE_PLUGIN
+#include "plugin/plugin_output.h"
+#endif
#include "version.h"
@@ -63,21 +67,6 @@ using namespace std;
t_program* g_program;
/**
- * Global types
- */
-
-t_type* g_type_void;
-t_type* g_type_string;
-t_type* g_type_binary;
-t_type* g_type_slist;
-t_type* g_type_bool;
-t_type* g_type_i8;
-t_type* g_type_i16;
-t_type* g_type_i32;
-t_type* g_type_i64;
-t_type* g_type_double;
-
-/**
* Global scope
*/
t_scope* g_scope;
@@ -143,16 +132,9 @@ char* g_time_str;
char* g_doctext;
/**
- * The location of the last parsed doctext comment.
- */
-int g_doctext_lineno;
-
-/**
* The First doctext comment
*/
char* g_program_doctext_candidate;
-int g_program_doctext_lineno = 0;
-PROGDOCTEXT_STATUS g_program_doctext_status = INVALID;
/**
* Whether or not negative field keys are accepted.
@@ -179,6 +161,7 @@ bool g_audit = false;
*/
bool g_return_failure = false;
bool g_audit_fatal = true;
+bool g_generator_failure = false;
/**
* Win32 doesn't have realpath, so use fallback implementation in that case,
@@ -1024,8 +1007,27 @@ void generate(t_program* program, const vector<string>& generator_strings) {
t_generator* generator = t_generator_registry::get_generator(program, *iter);
if (generator == NULL) {
+#ifdef THRIFT_ENABLE_PLUGIN
+ switch (plugin_output::delegateToPlugin(program, *iter)) {
+ case plugin_output::PLUGIN_NOT_FOUND:
+ pwarning(1, "Unable to get a generator for \"%s\".\n", iter->c_str());
+ g_generator_failure = true;
+ break;
+ case plugin_output::PLUGIN_FAILURE:
+ pwarning(1, "Plugin generator for \"%s\" failed.\n", iter->c_str());
+ g_generator_failure = true;
+ break;
+ case plugin_output::PLUGIN_SUCCEESS:
+ break;
+ default:
+ assert(false);
+ break;
+ }
+#else
pwarning(1, "Unable to get a generator for \"%s\".\n", iter->c_str());
- } else {
+ g_generator_failure = true;
+#endif
+ } else if (generator) {
pverbose("Generating \"%s\"\n", iter->c_str());
generator->generate_program();
delete generator;
@@ -1208,18 +1210,7 @@ int main(int argc, char** argv) {
}
// Initialize global types
- g_type_void = new t_base_type("void", t_base_type::TYPE_VOID);
- g_type_string = new t_base_type("string", t_base_type::TYPE_STRING);
- g_type_binary = new t_base_type("string", t_base_type::TYPE_STRING);
- ((t_base_type*)g_type_binary)->set_binary(true);
- g_type_slist = new t_base_type("string", t_base_type::TYPE_STRING);
- ((t_base_type*)g_type_slist)->set_string_list(true);
- g_type_bool = new t_base_type("bool", t_base_type::TYPE_BOOL);
- g_type_i8 = new t_base_type("i8", t_base_type::TYPE_I8);
- g_type_i16 = new t_base_type("i16", t_base_type::TYPE_I16);
- g_type_i32 = new t_base_type("i32", t_base_type::TYPE_I32);
- g_type_i64 = new t_base_type("i64", t_base_type::TYPE_I64);
- g_type_double = new t_base_type("double", t_base_type::TYPE_DOUBLE);
+ initGlobals();
if (g_audit) {
// Audit operation
@@ -1302,20 +1293,15 @@ int main(int argc, char** argv) {
// Clean up. Who am I kidding... this program probably orphans heap memory
// all over the place, but who cares because it is about to exit and it is
// all referenced and used by this wacky parse tree up until now anyways.
-
- delete g_type_void;
- delete g_type_string;
- delete g_type_bool;
- delete g_type_i8;
- delete g_type_i16;
- delete g_type_i32;
- delete g_type_i64;
- delete g_type_double;
+ clearGlobals();
// Finished
if (g_return_failure && g_audit_fatal) {
exit(2);
}
+ if (g_generator_failure) {
+ exit(3);
+ }
// Finished
return 0;
}
diff --git a/compiler/cpp/src/parse/parse.cc b/compiler/cpp/src/parse/parse.cc
index b22ee5281..81a557b15 100644
--- a/compiler/cpp/src/parse/parse.cc
+++ b/compiler/cpp/src/parse/parse.cc
@@ -29,3 +29,11 @@ t_type* t_type::get_true_type() {
}
return type;
}
+
+const t_type* t_type::get_true_type() const {
+ const t_type* type = this;
+ while (type->is_typedef()) {
+ type = ((t_typedef*)type)->get_type();
+ }
+ return type;
+}
diff --git a/compiler/cpp/src/parse/t_const_value.h b/compiler/cpp/src/parse/t_const_value.h
index 7e6e3f6b4..15366ad77 100644
--- a/compiler/cpp/src/parse/t_const_value.h
+++ b/compiler/cpp/src/parse/t_const_value.h
@@ -26,6 +26,11 @@
#include <vector>
#include <string>
+namespace plugin_output {
+template <typename From, typename To>
+void convert(From*, To&);
+}
+
/**
* A const value is something parsed that could be a map, set, list, struct
* or whatever.
@@ -141,6 +146,10 @@ private:
t_enum* enum_;
t_const_value_type valType_;
+
+ // to read enum_
+ template <typename From, typename To>
+ friend void plugin_output::convert(From*, To&);
};
#endif
diff --git a/compiler/cpp/src/parse/t_container.h b/compiler/cpp/src/parse/t_container.h
index 0d992b723..2cdcf7edd 100644
--- a/compiler/cpp/src/parse/t_container.h
+++ b/compiler/cpp/src/parse/t_container.h
@@ -33,9 +33,9 @@ public:
has_cpp_name_ = true;
}
- bool has_cpp_name() { return has_cpp_name_; }
+ bool has_cpp_name() const { return has_cpp_name_; }
- std::string get_cpp_name() { return cpp_name_; }
+ std::string get_cpp_name() const { return cpp_name_; }
bool is_container() const { return true; }
diff --git a/compiler/cpp/src/parse/t_doc.h b/compiler/cpp/src/parse/t_doc.h
index 9d310b72d..621513a3d 100644
--- a/compiler/cpp/src/parse/t_doc.h
+++ b/compiler/cpp/src/parse/t_doc.h
@@ -31,6 +31,7 @@ class t_doc {
public:
t_doc() : has_doc_(false) {}
+ virtual ~t_doc() {}
void set_doc(const std::string& doc) {
doc_ = doc;
diff --git a/compiler/cpp/src/parse/t_enum.h b/compiler/cpp/src/parse/t_enum.h
index 64f4ff4c8..268f89ff0 100644
--- a/compiler/cpp/src/parse/t_enum.h
+++ b/compiler/cpp/src/parse/t_enum.h
@@ -20,9 +20,11 @@
#ifndef T_ENUM_H
#define T_ENUM_H
-#include "t_enum_value.h"
#include <vector>
+#include "t_enum_value.h"
+#include "t_type.h"
+
/**
* An enumerated type. A list of constant objects with a name for the type.
*
@@ -35,7 +37,7 @@ public:
void append(t_enum_value* constant) { constants_.push_back(constant); }
- const std::vector<t_enum_value*>& get_constants() { return constants_; }
+ const std::vector<t_enum_value*>& get_constants() const { return constants_; }
t_enum_value* get_constant_by_name(const std::string& name) {
const std::vector<t_enum_value*>& enum_values = get_constants();
diff --git a/compiler/cpp/src/parse/t_enum_value.h b/compiler/cpp/src/parse/t_enum_value.h
index 5979f06a7..296029b24 100644
--- a/compiler/cpp/src/parse/t_enum_value.h
+++ b/compiler/cpp/src/parse/t_enum_value.h
@@ -20,6 +20,7 @@
#ifndef T_ENUM_VALUE_H
#define T_ENUM_VALUE_H
+#include <map>
#include <string>
#include "t_doc.h"
diff --git a/compiler/cpp/src/parse/t_field.h b/compiler/cpp/src/parse/t_field.h
index eece7bb14..8b459a351 100644
--- a/compiler/cpp/src/parse/t_field.h
+++ b/compiler/cpp/src/parse/t_field.h
@@ -20,10 +20,12 @@
#ifndef T_FIELD_H
#define T_FIELD_H
+#include <map>
#include <string>
#include <sstream>
#include "t_doc.h"
+#include "t_type.h"
// Forward declare for xsd_attrs
class t_struct;
@@ -58,7 +60,9 @@ public:
~t_field() {}
- t_type* get_type() const { return type_; }
+ t_type* get_type() { return type_; }
+
+ const t_type* get_type() const { return type_; }
const std::string& get_name() const { return name_; }
@@ -74,6 +78,8 @@ public:
t_const_value* get_value() { return value_; }
+ const t_const_value* get_value() const { return value_; }
+
void set_xsd_optional(bool xsd_optional) { xsd_optional_ = xsd_optional; }
bool get_xsd_optional() const { return xsd_optional_; }
diff --git a/compiler/cpp/src/parse/t_program.h b/compiler/cpp/src/parse/t_program.h
index 812106cb4..563e9e038 100644
--- a/compiler/cpp/src/parse/t_program.h
+++ b/compiler/cpp/src/parse/t_program.h
@@ -58,9 +58,7 @@
class t_program : public t_doc {
public:
t_program(std::string path, std::string name)
- : path_(path), name_(name), out_path_("./"), out_path_is_absolute_(false) {
- scope_ = new t_scope();
- }
+ : path_(path), name_(name), out_path_("./"), out_path_is_absolute_(false), scope_(new t_scope) {}
t_program(std::string path) : path_(path), out_path_("./"), out_path_is_absolute_(false) {
name_ = program_name(path);
@@ -250,6 +248,10 @@ public:
// Includes
+ void add_include(t_program* program) {
+ includes_.push_back(program);
+ }
+
void add_include(std::string path, std::string include_site) {
t_program* program = new t_program(path);
diff --git a/compiler/cpp/src/parse/t_scope.h b/compiler/cpp/src/parse/t_scope.h
index 5acb94e5b..565fd8fde 100644
--- a/compiler/cpp/src/parse/t_scope.h
+++ b/compiler/cpp/src/parse/t_scope.h
@@ -32,6 +32,11 @@
#include "t_map.h"
#include "t_list.h"
+namespace plugin_output {
+template <typename From, typename To>
+void convert(From*, To&);
+}
+
/**
* This represents a variable scope used for looking up predefined types and
* services. Typically, a scope is associated with a t_program. Scopes are not
@@ -167,6 +172,10 @@ private:
// Map of names to services
std::map<std::string, t_service*> services_;
+
+ // to list map entries
+ template <typename From, typename To>
+ friend void plugin_output::convert(From*, To&);
};
#endif
diff --git a/compiler/cpp/src/parse/t_service.h b/compiler/cpp/src/parse/t_service.h
index 2b01f9c45..6fa8398f1 100644
--- a/compiler/cpp/src/parse/t_service.h
+++ b/compiler/cpp/src/parse/t_service.h
@@ -51,6 +51,8 @@ public:
t_service* get_extends() { return extends_; }
+ const t_service* get_extends() const { return extends_; }
+
private:
std::vector<t_function*> functions_;
t_service* extends_;
diff --git a/compiler/cpp/src/parse/t_struct.h b/compiler/cpp/src/parse/t_struct.h
index d19447c36..1f48f91bf 100644
--- a/compiler/cpp/src/parse/t_struct.h
+++ b/compiler/cpp/src/parse/t_struct.h
@@ -127,7 +127,7 @@ public:
return true;
}
- const members_type& get_members() { return members_; }
+ const members_type& get_members() const { return members_; }
const members_type& get_sorted_members() { return members_in_id_order_; }
@@ -147,6 +147,16 @@ public:
return NULL;
}
+ const t_field* get_field_by_name(std::string field_name) const {
+ members_type::const_iterator m_iter;
+ for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) {
+ if ((*m_iter)->get_name() == field_name) {
+ return *m_iter;
+ }
+ }
+ return NULL;
+ }
+
private:
members_type members_;
members_type members_in_id_order_;
diff --git a/compiler/cpp/src/parse/t_type.h b/compiler/cpp/src/parse/t_type.h
index 416cc6fa3..bea4ee171 100644
--- a/compiler/cpp/src/parse/t_type.h
+++ b/compiler/cpp/src/parse/t_type.h
@@ -63,6 +63,7 @@ public:
const t_program* get_program() const { return program_; }
t_type* get_true_type();
+ const t_type* get_true_type() const;
// This function will break (maybe badly) unless 0 <= num <= 16.
static char nybble_to_xdigit(int num) {
diff --git a/compiler/cpp/src/plugin/Makefile.am b/compiler/cpp/src/plugin/Makefile.am
new file mode 100644
index 000000000..7e3c82d8b
--- /dev/null
+++ b/compiler/cpp/src/plugin/Makefile.am
@@ -0,0 +1,47 @@
+#
+# 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.
+#
+#
+# Contains some contributions under the Thrift Software License.
+# Please see doc/old-thrift-license.txt in the Thrift distribution for
+# details.
+
+AUTOMAKE_OPTIONS = subdir-objects
+
+if WITH_PLUGIN
+plugin_gen = plugin_types.h \
+ plugin_types.cpp \
+ plugin_constants.h \
+ plugin_constants.cpp
+
+BUILT_SOURCES = $(plugin_gen)
+gen.stamp: plugin.thrift $(top_builddir)/compiler/cpp/src/thrift-bootstrap
+ @$(RM) -f gen.tmp
+ @touch gen.tmp
+ $(top_builddir)/compiler/cpp/src/thrift-bootstrap -gen cpp -out . $<
+ @mv -f gen.tmp $@
+
+$(plugin_gen): gen.stamp
+ @if test -f $@; then :; else \
+ $(RM) -f gen.stamp; \
+ $(MAKE) $(AM_MAKEFLAGS) gen.stamp; \
+ fi
+
+clean-local:
+ $(RM) version.h windows/version.h $(plugin_gen)
+endif
diff --git a/compiler/cpp/src/plugin/plugin.cc b/compiler/cpp/src/plugin/plugin.cc
new file mode 100644
index 000000000..d969f5028
--- /dev/null
+++ b/compiler/cpp/src/plugin/plugin.cc
@@ -0,0 +1,503 @@
+/*
+ * 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.
+ */
+
+#include "plugin/plugin.h"
+
+#ifdef _WIN32
+#include <fcntl.h>
+#include <io.h>
+#endif
+
+#include <cassert>
+#include <iostream>
+
+#include <boost/bind.hpp>
+#include <boost/range/adaptor/map.hpp>
+#include <boost/range/algorithm/for_each.hpp>
+#include <boost/smart_ptr.hpp>
+
+#include "generate/t_generator.h"
+#include "plugin/type_util.h"
+#include "thrift/protocol/TBinaryProtocol.h"
+#include "thrift/transport/TBufferTransports.h"
+#include "thrift/transport/TFDTransport.h"
+
+#include "plugin/plugin_types.h"
+
+namespace apache {
+namespace thrift {
+namespace plugin {
+
+using apache::thrift::protocol::TBinaryProtocol;
+using apache::thrift::transport::TFDTransport;
+using apache::thrift::transport::TFramedTransport;
+
+#define THRIFT_CONVERT_FORWARD(from_type) \
+ template <> \
+ typename ToType<from_type>::type* convert_forward<from_type>(const from_type& from)
+
+#define THRIFT_CONVERT_COMPLETE_DECL(from_type) \
+ template <> \
+ void convert(const from_type& from, ToType<from_type>::type* to)
+
+#define THRIFT_CONVERT_UNARY_DECL(from_type) \
+ template <> \
+ typename ToType<from_type>::type* convert<from_type>(const from_type& from)
+
+#define THRIFT_CONVERSION_DECL(from_type) \
+ THRIFT_CONVERT_FORWARD(from_type); \
+ THRIFT_CONVERT_COMPLETE_DECL(from_type); \
+ THRIFT_CONVERT_UNARY_DECL(from_type)
+
+#define THRIFT_CONVERT_COMPLETE(from_type) \
+ THRIFT_CONVERSION_DECL(from_type) { \
+ ToType<from_type>::type* to = convert_forward(from); \
+ convert(from, to); \
+ return to; \
+ } \
+ THRIFT_CONVERT_COMPLETE_DECL(from_type)
+
+#define THRIFT_CONVERSION(from_type, ...) \
+ THRIFT_CONVERT_FORWARD(from_type) { \
+ (void)from; \
+ return new ToType<from_type>::type(__VA_ARGS__); \
+ } \
+ THRIFT_CONVERT_COMPLETE(from_type)
+
+#define THRIFT_ASSIGN_DOC() \
+ do { \
+ if (from.__isset.doc) \
+ to->set_doc(from.doc); \
+ } while (0)
+
+#define THRIFT_ASSIGN_ANNOTATIONS() \
+ THRIFT_ASSIGN_DOC(); \
+ do { \
+ if (from.__isset.annotations) \
+ to->annotations_ = from.annotations; \
+ } while (0)
+
+#define THRIFT_ASSIGN_METADATA() \
+ do { \
+ to->set_name(from.metadata.name); \
+ if (from.metadata.__isset.doc) \
+ to->set_doc(from.metadata.doc); \
+ if (from.metadata.__isset.annotations) \
+ to->annotations_ = from.metadata.annotations; \
+ } while (0)
+
+::t_program* g_program = 0;
+
+template <typename C, typename S>
+struct TypeCache {
+ C* operator[](const int64_t& k) {
+ typename std::map<int64_t, C*>::iterator it = cache.find(k);
+ if (it != cache.end()) {
+ return it->second;
+ } else {
+ typename std::map<int64_t, S>::const_iterator cit = source->find(k);
+ if (cit == source->end()) {
+ throw ThriftPluginError("Type not found");
+ }
+ return (cache)[k] = convert_forward(cit->second);
+ }
+ }
+
+ void compileAll() {
+ boost::for_each(*source | boost::adaptors::map_keys,
+ boost::bind(&TypeCache::compile, this, _1));
+ }
+
+ std::map<int64_t, S> const* source;
+
+protected:
+ std::map<int64_t, C*> cache;
+
+private:
+ void compile(const int64_t& k) {
+ typename std::map<int64_t, S>::const_iterator cit = source->find(k);
+ if (cit == source->end()) {
+ throw ThriftPluginError("Type not found ");
+ }
+ convert(cit->second, (*this)[k]);
+ }
+};
+std::map<int64_t, ::t_program*> g_program_cache;
+TypeCache< ::t_type, t_type> g_type_cache;
+TypeCache< ::t_const, t_const> g_const_cache;
+TypeCache< ::t_service, t_service> g_service_cache;
+
+void set_global_cache(const TypeRegistry& from) {
+ g_type_cache.source = &from.types;
+ g_const_cache.source = &from.constants;
+ g_service_cache.source = &from.services;
+
+ g_type_cache.compileAll();
+ g_const_cache.compileAll();
+ g_service_cache.compileAll();
+}
+
+template <typename T>
+T* resolve_type(int64_t name) {
+ return reinterpret_cast<T*>(g_type_cache[name]);
+}
+
+::t_const* resolve_const(int64_t name) {
+ return g_const_cache[name];
+}
+
+::t_service* resolve_service(int64_t name) {
+ return g_service_cache[name];
+}
+
+THRIFT_CONVERT_FORWARD(t_base_type) {
+#define T_BASETYPE_CASE(type) \
+ case t_base::TYPE_##type: \
+ t = ::t_base_type::TYPE_##type; \
+ break
+
+ ::t_base_type::t_base t = ::t_base_type::TYPE_VOID;
+ bool is_binary = false;
+ switch (from.value) {
+ T_BASETYPE_CASE(VOID);
+ T_BASETYPE_CASE(STRING);
+ T_BASETYPE_CASE(BOOL);
+ T_BASETYPE_CASE(I8);
+ T_BASETYPE_CASE(I16);
+ T_BASETYPE_CASE(I32);
+ T_BASETYPE_CASE(I64);
+ T_BASETYPE_CASE(DOUBLE);
+ case t_base::TYPE_BINARY:
+ t = ::t_base_type::TYPE_STRING;
+ is_binary = true;
+ break;
+ }
+ ::t_base_type* to = new ::t_base_type(from.metadata.name, t);
+ to->set_binary(is_binary);
+ return to;
+#undef T_BASETYPE_CASE
+}
+THRIFT_CONVERT_COMPLETE(t_base_type) {
+ THRIFT_ASSIGN_METADATA();
+}
+
+THRIFT_CONVERT_FORWARD(t_typedef) {
+ ::t_typedef* to;
+ if (from.forward) {
+ to = new ::t_typedef(g_program_cache[from.metadata.program_id], from.symbolic, true);
+ } else {
+ to = new ::t_typedef(g_program_cache[from.metadata.program_id],
+ resolve_type< ::t_type>(from.type), from.symbolic);
+ }
+ return to;
+}
+THRIFT_CONVERT_COMPLETE(t_typedef) {
+ THRIFT_ASSIGN_METADATA();
+}
+THRIFT_CONVERSION(t_enum_value, from.name, from.value) {
+ assert(to);
+ THRIFT_ASSIGN_ANNOTATIONS();
+}
+THRIFT_CONVERSION(t_enum, g_program_cache[from.metadata.program_id]) {
+ assert(to);
+ THRIFT_ASSIGN_METADATA();
+ boost::for_each(from.constants | boost::adaptors::transformed(convert<t_enum_value>),
+ boost::bind(&::t_enum::append, to, _1));
+}
+THRIFT_CONVERSION(t_list, resolve_type< ::t_type>(from.elem_type)) {
+ assert(to);
+ THRIFT_ASSIGN_METADATA();
+ if (from.__isset.cpp_name)
+ to->set_cpp_name(from.cpp_name);
+}
+THRIFT_CONVERSION(t_set, resolve_type< ::t_type>(from.elem_type)) {
+ assert(to);
+ THRIFT_ASSIGN_METADATA();
+ if (from.__isset.cpp_name)
+ to->set_cpp_name(from.cpp_name);
+}
+THRIFT_CONVERSION(t_map,
+ resolve_type< ::t_type>(from.key_type),
+ resolve_type< ::t_type>(from.val_type)) {
+ assert(to);
+ THRIFT_ASSIGN_METADATA();
+ if (from.__isset.cpp_name)
+ to->set_cpp_name(from.cpp_name);
+}
+THRIFT_CONVERSION(t_const_value, ) {
+#define T_CONST_VALUE_CASE(type) \
+ if (from.__isset.type##_val) \
+ to->set_##type(from.type##_val)
+
+ assert(to);
+ if (from.__isset.map_val) {
+ to->set_map();
+ for (std::map<t_const_value, t_const_value>::const_iterator it = from.map_val.begin();
+ it != from.map_val.end(); it++) {
+ to->add_map(convert(it->first), convert(it->second));
+ }
+ } else if (from.__isset.list_val) {
+ to->set_list();
+ boost::for_each(from.list_val | boost::adaptors::transformed(&convert<t_const_value>),
+ boost::bind(&::t_const_value::add_list, to, _1));
+ } else
+ T_CONST_VALUE_CASE(string);
+ else T_CONST_VALUE_CASE(integer);
+ else T_CONST_VALUE_CASE(double);
+ else {
+ T_CONST_VALUE_CASE(identifier);
+ if (from.__isset.enum_val)
+ to->set_enum(resolve_type< ::t_enum>(from.enum_val));
+ }
+#undef T_CONST_VALUE_CASE
+}
+THRIFT_CONVERSION(t_field, resolve_type< ::t_type>(from.type), from.name, from.key) {
+ assert(to);
+ THRIFT_ASSIGN_ANNOTATIONS();
+ to->set_reference(from.reference);
+ to->set_req(static_cast< ::t_field::e_req>(from.req));
+ if (from.__isset.value) {
+ to->set_value(convert(from.value));
+ }
+}
+THRIFT_CONVERSION(t_struct, g_program_cache[from.metadata.program_id]) {
+ assert(to);
+ THRIFT_ASSIGN_METADATA();
+ to->set_union(from.is_union);
+ to->set_xception(from.is_xception);
+ boost::for_each(from.members | boost::adaptors::transformed(convert<t_field>),
+ boost::bind(&::t_struct::append, to, _1));
+}
+THRIFT_CONVERSION(t_const,
+ resolve_type< ::t_type>(from.type),
+ from.name,
+ convert<t_const_value>(from.value)) {
+ assert(to);
+ THRIFT_ASSIGN_DOC();
+}
+
+THRIFT_CONVERSION(t_function,
+ resolve_type< ::t_type>(from.returntype),
+ from.name,
+ resolve_type< ::t_struct>(from.arglist),
+ resolve_type< ::t_struct>(from.xceptions),
+ from.is_oneway) {
+ assert(to);
+ THRIFT_ASSIGN_DOC();
+}
+
+THRIFT_CONVERSION(t_service, g_program_cache[from.metadata.program_id]) {
+ assert(to);
+ assert(from.metadata.program_id);
+ assert(g_program_cache[from.metadata.program_id]);
+ THRIFT_ASSIGN_METADATA();
+
+ boost::for_each(from.functions | boost::adaptors::transformed(convert<t_function>),
+ boost::bind(&::t_service::add_function, to, _1));
+
+ if (from.__isset.extends_)
+ to->set_extends(resolve_service(from.extends_));
+}
+
+THRIFT_CONVERT_FORWARD(t_type) {
+#define T_TYPE_CASE_FW_T(case, type) \
+ if (from.__isset.case##_val) \
+ return convert_forward<type>(from.case##_val)
+#define T_TYPE_CASE_FW(case) T_TYPE_CASE_FW_T(case, t_##case)
+
+ T_TYPE_CASE_FW(base_type);
+ T_TYPE_CASE_FW(typedef);
+ T_TYPE_CASE_FW(enum);
+ T_TYPE_CASE_FW(struct);
+ T_TYPE_CASE_FW_T(xception, t_struct);
+ T_TYPE_CASE_FW(list);
+ T_TYPE_CASE_FW(set);
+ T_TYPE_CASE_FW(map);
+ T_TYPE_CASE_FW(service);
+ throw ThriftPluginError("Invalid data: Type union has no value.");
+#undef T_TYPE_CASE_FW_T
+#undef T_TYPE_CASE_FW
+}
+THRIFT_CONVERT_COMPLETE(t_type) {
+#define T_TYPE_CASE_T(case, type) \
+ else if (from.__isset.case##_val) \
+ convert<type, ::type>(from.case##_val, reinterpret_cast< ::type*>(to))
+#define T_TYPE_CASE(case) T_TYPE_CASE_T(case, t_##case)
+
+ if (false) {
+ }
+ T_TYPE_CASE(base_type);
+ T_TYPE_CASE(typedef);
+ T_TYPE_CASE(enum);
+ T_TYPE_CASE(struct);
+ T_TYPE_CASE_T(xception, t_struct);
+ T_TYPE_CASE(list);
+ T_TYPE_CASE(set);
+ T_TYPE_CASE(map);
+ T_TYPE_CASE(service);
+ else {
+ throw ThriftPluginError("Invalid data: Type union has no value.");
+ }
+#undef T_TYPE_CASE_T
+#undef T_TYPE_CASE
+}
+
+THRIFT_CONVERSION(t_scope, ) {
+ assert(to);
+#define T_SCOPE_RESOLVE(type, name, a) \
+ for (std::vector<int64_t>::const_iterator it = from.name##s.begin(); it != from.name##s.end(); \
+ it++) { \
+ ::t_##type* t = resolve_##type a(*it); \
+ to->add_##name(t->get_name(), t); \
+ }
+ T_SCOPE_RESOLVE(type, type, < ::t_type>);
+ T_SCOPE_RESOLVE(const, constant, );
+ T_SCOPE_RESOLVE(service, service, );
+#undef T_SCOPE_RESOLVE
+}
+
+THRIFT_CONVERT_FORWARD(t_program) {
+ ::t_program* to = new ::t_program(from.path, from.name);
+ for (std::vector<t_program>::const_iterator it = from.includes.begin(); it != from.includes.end();
+ it++) {
+ to->add_include(convert_forward(*it));
+ }
+ g_program_cache[from.program_id] = to;
+ return to;
+}
+THRIFT_CONVERT_COMPLETE(t_program) {
+ assert(to);
+ g_program = to;
+ convert<t_scope, ::t_scope>(from.scope, to->scope());
+ THRIFT_ASSIGN_DOC();
+
+ to->set_out_path(from.out_path, from.out_path_is_absolute);
+
+ boost::for_each(from.typedefs | boost::adaptors::transformed(&resolve_type< ::t_typedef>),
+ boost::bind(&::t_program::add_typedef, to, _1));
+ boost::for_each(from.enums | boost::adaptors::transformed(&resolve_type< ::t_enum>),
+ boost::bind(&::t_program::add_enum, to, _1));
+ for (std::vector<int64_t>::const_iterator it = from.objects.begin(); it != from.objects.end();
+ it++) {
+ ::t_struct* t2 = resolve_type< ::t_struct>(*it);
+ if (t2->is_xception()) {
+ to->add_xception(t2);
+ } else {
+ to->add_struct(t2);
+ }
+ }
+ boost::for_each(from.consts | boost::adaptors::transformed(&resolve_const),
+ boost::bind(&::t_program::add_const, to, _1));
+ boost::for_each(from.services | boost::adaptors::transformed(&resolve_service),
+ boost::bind(&::t_program::add_service, to, _1));
+
+ for (std::vector<t_program>::const_iterator it = from.includes.begin(); it != from.includes.end();
+ it++) {
+ convert(*it, g_program_cache[it->program_id]);
+ }
+ std::for_each(from.c_includes.begin(), from.c_includes.end(),
+ boost::bind(&::t_program::add_c_include, to, _1));
+ std::for_each(from.cpp_includes.begin(), from.cpp_includes.end(),
+ boost::bind(&::t_program::add_cpp_include, to, _1));
+ for (std::map<std::string, std::string>::const_iterator it = from.namespaces.begin();
+ it != from.namespaces.end(); it++) {
+ to->set_namespace(it->first, it->second);
+ }
+
+ to->set_include_prefix(from.include_prefix);
+ to->set_namespace(from.namespace_);
+}
+
+int GeneratorPlugin::exec(int, char* []) {
+#ifdef _WIN32
+ _setmode(fileno(stdin), _O_BINARY);
+#endif
+ boost::shared_ptr<TFramedTransport> transport(
+ new TFramedTransport(boost::make_shared<TFDTransport>(fileno(stdin))));
+ TBinaryProtocol proto(transport);
+ GeneratorInput input;
+ try {
+ input.read(&proto);
+ } catch (std::exception& err) {
+ std::cerr << "Error while receiving plugin data: " << err.what() << std::endl;
+ return -1;
+ }
+ initGlobals();
+ ::t_program* p = g_program = convert_forward(input.program);
+ set_global_cache(input.type_registry);
+ convert(input.program, p);
+
+ int ret = generate(p, input.parsed_options);
+ clearGlobals();
+
+ return ret;
+}
+
+::t_const_value::t_const_value_type const_value_case(const t_const_value& v) {
+ if (v.__isset.map_val)
+ return ::t_const_value::CV_MAP;
+ if (v.__isset.list_val)
+ return ::t_const_value::CV_LIST;
+ if (v.__isset.string_val)
+ return ::t_const_value::CV_STRING;
+ if (v.__isset.integer_val)
+ return ::t_const_value::CV_INTEGER;
+ if (v.__isset.double_val)
+ return ::t_const_value::CV_DOUBLE;
+ if (v.__isset.identifier_val)
+ return ::t_const_value::CV_IDENTIFIER;
+ if (v.__isset.enum_val)
+ return ::t_const_value::CV_IDENTIFIER;
+ throw ThriftPluginError("Unknown const value type");
+}
+
+bool t_const_value::operator<(const t_const_value& that) const {
+ ::t_const_value::t_const_value_type t1 = const_value_case(*this);
+ ::t_const_value::t_const_value_type t2 = const_value_case(that);
+ if (t1 != t2)
+ return t1 < t2;
+ switch (t1) {
+ case ::t_const_value::CV_INTEGER:
+ return integer_val < that.integer_val;
+ case ::t_const_value::CV_DOUBLE:
+ return double_val < that.double_val;
+ case ::t_const_value::CV_STRING:
+ return string_val < that.string_val;
+ case ::t_const_value::CV_MAP:
+ if (that.map_val.empty())
+ return false;
+ else if (map_val.empty())
+ return true;
+ else
+ return map_val.begin()->first < that.map_val.begin()->first;
+ case ::t_const_value::CV_LIST:
+ if (that.list_val.empty())
+ return false;
+ else if (list_val.empty())
+ return true;
+ else
+ return list_val.front() < that.list_val.front();
+ case ::t_const_value::CV_IDENTIFIER:
+ return integer_val < that.integer_val;
+ }
+ throw ThriftPluginError("Unknown const value type");
+}
+}
+}
+}
diff --git a/compiler/cpp/src/plugin/plugin.h b/compiler/cpp/src/plugin/plugin.h
new file mode 100644
index 000000000..705cd41ff
--- /dev/null
+++ b/compiler/cpp/src/plugin/plugin.h
@@ -0,0 +1,44 @@
+/*
+ * 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 T_PLUGIN_PLUGIN_H
+#define T_PLUGIN_PLUGIN_H
+
+#include "thrift/Thrift.h"
+
+class t_program;
+
+namespace apache {
+namespace thrift {
+namespace plugin {
+
+struct ThriftPluginError : public apache::thrift::TException {
+ ThriftPluginError(const std::string& msg) : apache::thrift::TException(msg) {}
+};
+
+class GeneratorPlugin {
+public:
+ int exec(int argc, char* argv[]);
+ virtual int generate(::t_program*, const std::map<std::string, std::string>&) = 0;
+};
+}
+}
+}
+
+#endif
diff --git a/compiler/cpp/src/plugin/plugin.thrift b/compiler/cpp/src/plugin/plugin.thrift
new file mode 100644
index 000000000..a93873da1
--- /dev/null
+++ b/compiler/cpp/src/plugin/plugin.thrift
@@ -0,0 +1,202 @@
+/*
+ * 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.
+ */
+
+namespace as3 org.apache.thrift.plugin
+namespace cpp apache.thrift.plugin
+namespace csharp Thrift.Plugin
+namespace d thrift.plugin
+namespace delphi Thrift.Plugin
+namespace erl thrift.plugin
+namespace go thrift
+namespace haxe org.apache.thrift.plugin
+namespace hs Thrift.Plugin
+namespace java org.apache.thrift.plugin
+namespace ocaml Thrift
+namespace perl Thrift.Plugin
+namespace php thrift.plugin
+namespace py thrift.plugin
+namespace rb Thrift
+
+typedef i64 t_program_id
+typedef i64 t_type_id
+typedef i64 t_const_id
+typedef i64 t_service_id
+
+enum t_base {
+ TYPE_VOID
+ TYPE_STRING
+ TYPE_BOOL
+ TYPE_I8
+ TYPE_I16
+ TYPE_I32
+ TYPE_I64
+ TYPE_DOUBLE
+ TYPE_BINARY
+}
+
+struct TypeMetadata {
+ 1: required string name
+ 2: required t_program_id program_id
+ 99: optional map<string, string> annotations
+ 100: optional string doc
+}
+
+struct t_base_type {
+ 1: required TypeMetadata metadata
+ 2: required t_base value
+}
+
+struct t_list {
+ 1: required TypeMetadata metadata
+ 2: optional string cpp_name
+ 3: required t_type_id elem_type
+}
+
+struct t_set {
+ 1: required TypeMetadata metadata
+ 2: optional string cpp_name
+ 3: required t_type_id elem_type
+}
+
+struct t_map {
+ 1: required TypeMetadata metadata
+ 2: optional string cpp_name
+ 3: required t_type_id key_type
+ 4: required t_type_id val_type
+}
+
+struct t_typedef {
+ 1: required TypeMetadata metadata
+ 2: required t_type_id type
+ 3: required string symbolic
+ 4: required bool forward
+}
+
+struct t_enum_value {
+ 1: required string name
+ 2: required i32 value
+ 99: optional map<string, string> annotations
+ 100: optional string doc
+}
+struct t_enum {
+ 1: required TypeMetadata metadata
+ 2: required list<t_enum_value> constants
+}
+
+enum Requiredness {
+ T_REQUIRED = 0
+ T_OPTIONAL = 1
+ T_OPT_IN_REQ_OUT = 2
+}
+
+union t_const_value {
+ 1: optional map<t_const_value, t_const_value> map_val
+ 2: optional list<t_const_value> list_val
+ 3: optional string string_val
+ 4: optional i64 integer_val
+ 5: optional double double_val
+ 6: optional string identifier_val
+ 7: optional t_type_id enum_val
+}
+struct t_const {
+ 1: required string name
+ 2: required t_type_id type
+ 3: required t_const_value value
+ 100: optional string doc
+}
+struct t_struct {
+ 1: required TypeMetadata metadata
+ 2: required list<t_field> members
+ 3: required bool is_union
+ 4: required bool is_xception
+}
+struct t_field {
+ 1: required string name
+ 2: required t_type_id type
+ 3: required i32 key
+ 4: required Requiredness req
+ 5: optional t_const_value value
+ 10: required bool reference
+ 99: optional map<string, string> annotations
+ 100: optional string doc
+}
+struct t_function {
+ 1: required string name
+ 2: required t_type_id returntype
+ 3: required t_type_id arglist
+ 4: required t_type_id xceptions
+ 5: required bool is_oneway
+ 100: optional string doc
+}
+struct t_service {
+ 1: required TypeMetadata metadata
+ 2: required list<t_function> functions
+ 3: optional t_service_id extends_
+}
+union t_type {
+ 1: optional t_base_type base_type_val
+ 2: optional t_typedef typedef_val
+ 3: optional t_enum enum_val
+ 4: optional t_struct struct_val
+ 5: optional t_struct xception_val
+ 6: optional t_list list_val
+ 7: optional t_set set_val
+ 8: optional t_map map_val
+ 9: optional t_service service_val
+}
+struct t_scope {
+ 1: required list<t_type_id> types
+ 2: required list<t_const_id> constants
+ 3: required list<t_service_id> services
+}
+
+struct TypeRegistry {
+ 1: required map<t_type_id, t_type> types
+ 2: required map<t_const_id, t_const> constants
+ 3: required map<t_service_id, t_service> services
+}
+
+struct t_program {
+ 1: required string name
+ 2: required t_program_id program_id
+ 3: required string path
+ 4: required string namespace_
+ 5: required string out_path
+ 6: required bool out_path_is_absolute
+ 8: required list<t_program> includes
+ 9: required string include_prefix
+ 10: required t_scope scope
+
+ 11: required list<t_type_id> typedefs
+ 12: required list<t_type_id> enums
+ 13: required list<t_const_id> consts
+ 14: required list<t_type_id> objects
+ 15: required list<t_service_id> services
+
+ 16: required map<string, string> namespaces
+ 17: required list<string> cpp_includes
+ 18: required list<string> c_includes
+ 100: optional string doc
+}
+
+struct GeneratorInput {
+ 1: required t_program program
+ 2: required TypeRegistry type_registry
+ 3: required map<string, string> parsed_options
+}
diff --git a/compiler/cpp/src/plugin/plugin_output.cc b/compiler/cpp/src/plugin/plugin_output.cc
new file mode 100644
index 000000000..1ab015e84
--- /dev/null
+++ b/compiler/cpp/src/plugin/plugin_output.cc
@@ -0,0 +1,410 @@
+/*
+ * 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.
+ */
+
+#ifdef _WIN32
+#include <cstdio>
+#include <fcntl.h>
+#include <io.h>
+#include <iostream>
+#define THRIFT_POPEN(cmd) _popen(cmd, "wb")
+#define THRIFT_PCLOSE _pclose
+#else
+#define THRIFT_POPEN(cmd) popen(cmd, "w")
+#define THRIFT_PCLOSE pclose
+#endif
+
+#include "plugin/plugin_output.h"
+
+#include <boost/range/adaptor/map.hpp>
+#include <boost/range/algorithm/copy.hpp>
+#include <boost/range/algorithm/transform.hpp>
+#include <boost/smart_ptr.hpp>
+
+#include "generate/t_generator.h"
+#include "plugin/plugin.h"
+#include "plugin/type_util.h"
+#include "thrift/protocol/TBinaryProtocol.h"
+#include "thrift/transport/TBufferTransports.h"
+#include "thrift/transport/TFDTransport.h"
+
+#include "plugin/plugin_types.h"
+
+namespace plugin_output {
+
+template <typename From>
+typename apache::thrift::plugin::ToType<From>::type convert(From* from) {
+ typename apache::thrift::plugin::ToType<From>::type to;
+ convert(from, to);
+ return to;
+}
+
+using apache::thrift::protocol::TBinaryProtocol;
+using apache::thrift::transport::TFDTransport;
+using apache::thrift::transport::TFramedTransport;
+
+using namespace apache::thrift;
+
+#define THRIFT_CONVERSION_N(from_type, to_type) \
+ template <> \
+ void convert<from_type, to_type>(from_type * from, to_type & to)
+#define THRIFT_CONVERSION(type) THRIFT_CONVERSION_N(::type, plugin::type)
+
+#define THRIFT_ASSIGN_N(from_name, to_name, prefix) \
+ do { \
+ if (from) \
+ to.__set_##to_name(prefix(from->from_name)); \
+ } while (0)
+
+#define THRIFT_ASSIGN(name) THRIFT_ASSIGN_N(get_##name(), name, )
+#define THRIFT_ASSIGN_CONVERT(type, from_name, to_name) \
+ do { \
+ if (from && from->from_name) { \
+ to.__set_##to_name(convert(from->from_name)); \
+ } \
+ } while (0)
+
+#define THRIFT_ASSIGN_OPT(name) \
+ do { \
+ if (from->has_##name()) \
+ THRIFT_ASSIGN(name); \
+ } while (0)
+
+#define THRIFT_ASSIGN_LIST_N(type, from_name, to_name) \
+ do { \
+ if (from && !from->from_name.empty()) { \
+ std::transform(from->from_name.begin(), \
+ from->from_name.end(), \
+ std::back_inserter(to.to_name), \
+ convert< ::type>); \
+ } \
+ } while (0)
+
+#define THRIFT_ASSIGN_METADATA() convert(reinterpret_cast<t_type*>(from), to.metadata)
+
+// To avoid multiple instances of same type, t_type, t_const and t_service are stored in one place
+// and referenced by ID.
+template <typename T>
+struct TypeCache {
+ typedef typename plugin::ToType<T>::type to_type;
+ std::map<int64_t, to_type> cache;
+
+ template <typename T2>
+ int64_t store(T2* t) {
+ intptr_t id = reinterpret_cast<intptr_t>(t);
+ if (id) {
+ typename std::map<int64_t, to_type>::iterator it = cache.find(id);
+ if (it == cache.end()) {
+ // HACK: fake resolve for recursive type
+ cache.insert(std::make_pair(id, to_type()));
+ // overwrite with true value
+ cache[id] = convert(t);
+ }
+ }
+ return static_cast<int64_t>(id);
+ }
+
+ void clear() { cache.clear(); }
+};
+
+template <typename T>
+int64_t store_type(T* t);
+
+#define T_STORE(type) \
+ TypeCache<t_##type> type##_cache; \
+ template <> \
+ plugin::t_##type##_id store_type<t_##type>(t_##type * t) { \
+ return type##_cache.store<t_##type>(t); \
+ }
+T_STORE(type)
+T_STORE(const)
+T_STORE(service)
+#undef T_STORE
+
+#define THRIFT_ASSIGN_ID_N(t, from_name, to_name) \
+ do { \
+ if (from && from->from_name) \
+ to.__set_##to_name(store_type<t>(from->from_name)); \
+ } while (0)
+
+#define THRIFT_ASSIGN_ID(name) THRIFT_ASSIGN_ID_N(t_type, get_##name(), name)
+
+#define THRIFT_ASSIGN_LIST_ID(t, name) \
+ do { \
+ if (from && !from->get_##name##s().empty()) { \
+ std::transform(from->get_##name##s().begin(), \
+ from->get_##name##s().end(), \
+ std::back_inserter(to.name##s), \
+ &store_type<t>); \
+ } \
+ } while (0)
+
+THRIFT_CONVERSION_N(::t_type, plugin::TypeMetadata) {
+ to.program_id = reinterpret_cast<int64_t>(from->get_program());
+ THRIFT_ASSIGN_N(annotations_, annotations, );
+ if (from->has_doc()) {
+ to.__set_doc(from->get_doc());
+ }
+ THRIFT_ASSIGN(name);
+}
+
+THRIFT_CONVERSION(t_typedef) {
+ THRIFT_ASSIGN_METADATA();
+ THRIFT_ASSIGN_ID(type);
+ THRIFT_ASSIGN(symbolic);
+ THRIFT_ASSIGN_N(is_forward_typedef(), forward, );
+}
+
+THRIFT_CONVERSION(t_enum_value) {
+ THRIFT_ASSIGN_OPT(doc);
+ THRIFT_ASSIGN(name);
+ THRIFT_ASSIGN(value);
+}
+
+THRIFT_CONVERSION(t_enum) {
+ THRIFT_ASSIGN_METADATA();
+ THRIFT_ASSIGN_LIST_N(t_enum_value, get_constants(), constants);
+}
+
+THRIFT_CONVERSION(t_const_value) {
+ switch (from->get_type()) {
+ case t_const_value::CV_INTEGER:
+ THRIFT_ASSIGN_N(get_integer(), integer_val, );
+ break;
+ case t_const_value::CV_DOUBLE:
+ THRIFT_ASSIGN_N(get_double(), double_val, );
+ break;
+ case t_const_value::CV_STRING:
+ THRIFT_ASSIGN_N(get_string(), string_val, );
+ break;
+ case t_const_value::CV_IDENTIFIER:
+ THRIFT_ASSIGN_ID_N(t_type, enum_, enum_val);
+ THRIFT_ASSIGN_N(get_identifier(), identifier_val, );
+ break;
+ case t_const_value::CV_MAP:
+ to.__isset.map_val = true;
+ if (from && !from->get_map().empty()) {
+ for (std::map< ::t_const_value*, ::t_const_value*>::const_iterator it
+ = from->get_map().begin();
+ it != from->get_map().end();
+ it++) {
+ to.map_val.insert(std::make_pair(convert(it->first), convert(it->second)));
+ }
+ }
+ break;
+ case t_const_value::CV_LIST:
+ to.__isset.list_val = true;
+ THRIFT_ASSIGN_LIST_N(t_const_value, get_list(), list_val);
+ break;
+ default:
+ throw plugin::ThriftPluginError("const value has no value");
+ }
+}
+THRIFT_CONVERSION(t_const) {
+ THRIFT_ASSIGN_OPT(doc);
+ THRIFT_ASSIGN(name);
+ THRIFT_ASSIGN_ID(type);
+ THRIFT_ASSIGN_CONVERT(t_const_value, get_value(), value);
+}
+THRIFT_CONVERSION(t_field) {
+ THRIFT_ASSIGN_OPT(doc);
+ THRIFT_ASSIGN(name);
+ THRIFT_ASSIGN(key);
+ THRIFT_ASSIGN_N(get_req(), req, (plugin::Requiredness::type));
+ THRIFT_ASSIGN(reference);
+ THRIFT_ASSIGN_ID(type);
+ THRIFT_ASSIGN_CONVERT(t_const_value, get_value(), value);
+}
+THRIFT_CONVERSION(t_struct) {
+ THRIFT_ASSIGN_METADATA();
+ THRIFT_ASSIGN_LIST_N(t_field, get_members(), members);
+ THRIFT_ASSIGN_N(is_union(), is_union, );
+ THRIFT_ASSIGN_N(is_xception(), is_xception, );
+}
+THRIFT_CONVERSION(t_function) {
+ THRIFT_ASSIGN_OPT(doc);
+ THRIFT_ASSIGN(name);
+ THRIFT_ASSIGN_ID(returntype);
+ THRIFT_ASSIGN_N(is_oneway(), is_oneway, );
+ THRIFT_ASSIGN_ID(arglist);
+ THRIFT_ASSIGN_ID(xceptions);
+}
+
+THRIFT_CONVERSION(t_list) {
+ THRIFT_ASSIGN_METADATA();
+ THRIFT_ASSIGN_OPT(cpp_name);
+ THRIFT_ASSIGN_ID(elem_type);
+}
+THRIFT_CONVERSION(t_set) {
+ THRIFT_ASSIGN_METADATA();
+ THRIFT_ASSIGN_OPT(cpp_name);
+ THRIFT_ASSIGN_ID(elem_type);
+}
+THRIFT_CONVERSION(t_map) {
+ THRIFT_ASSIGN_METADATA();
+ THRIFT_ASSIGN_OPT(cpp_name);
+ THRIFT_ASSIGN_ID(key_type);
+ THRIFT_ASSIGN_ID(val_type);
+}
+
+THRIFT_CONVERSION(t_service) {
+ THRIFT_ASSIGN_METADATA();
+ THRIFT_ASSIGN_LIST_N(t_function, get_functions(), functions);
+ THRIFT_ASSIGN_ID_N(t_service, get_extends(), extends_);
+}
+
+THRIFT_CONVERSION(t_base_type) {
+ THRIFT_ASSIGN_METADATA();
+ if (from->is_binary()) {
+ to.value = plugin::t_base::TYPE_BINARY;
+ } else {
+ switch (from->get_base()) {
+#define T_BASETYPE_CASE(name) \
+ case t_base_type::TYPE_##name: \
+ to.value = plugin::t_base::TYPE_##name; \
+ break
+ T_BASETYPE_CASE(VOID);
+ T_BASETYPE_CASE(STRING);
+ T_BASETYPE_CASE(BOOL);
+ T_BASETYPE_CASE(I8);
+ T_BASETYPE_CASE(I16);
+ T_BASETYPE_CASE(I32);
+ T_BASETYPE_CASE(I64);
+ T_BASETYPE_CASE(DOUBLE);
+ default:
+ throw plugin::ThriftPluginError("Base type union has no value");
+ break;
+#undef T_BASETYPE_CASE
+ }
+ }
+}
+THRIFT_CONVERSION(t_type) {
+#define T_CONVERT_UNION_N(name, type) \
+ else if (from->is_##name()) { \
+ to.__isset.name##_val = true; \
+ convert(reinterpret_cast< ::type*>(from), to.name##_val); \
+ }
+#define T_CONVERT_UNION(name) T_CONVERT_UNION_N(name, t_##name)
+ if (false) {
+ }
+ T_CONVERT_UNION(base_type)
+ T_CONVERT_UNION(typedef)
+ T_CONVERT_UNION(enum)
+ T_CONVERT_UNION(struct)
+ T_CONVERT_UNION_N(xception, t_struct)
+ T_CONVERT_UNION(list)
+ T_CONVERT_UNION(set)
+ T_CONVERT_UNION(map)
+ T_CONVERT_UNION(service)
+ else {
+ throw plugin::ThriftPluginError("Type union has no value");
+ }
+#undef T_CONVERT_UNION_N
+#undef T_CONVERT_UNION
+}
+
+THRIFT_CONVERSION(t_scope) {
+#define T_SCOPE_ASSIGN(name, type) \
+ boost::copy(from->name##s_ | boost::adaptors::map_values \
+ | boost::adaptors::transformed(&store_type<type>), \
+ std::back_inserter(to.name##s))
+ T_SCOPE_ASSIGN(type, t_type);
+ T_SCOPE_ASSIGN(constant, t_const);
+ T_SCOPE_ASSIGN(service, t_service);
+#undef T_SCOPE_ASSIGN
+}
+
+void get_global_cache(plugin::TypeRegistry& reg) {
+ reg.types = type_cache.cache;
+ reg.constants = const_cache.cache;
+ reg.services = service_cache.cache;
+}
+
+void clear_global_cache() {
+ type_cache.clear();
+ const_cache.clear();
+ service_cache.clear();
+}
+
+THRIFT_CONVERSION(t_program) {
+ THRIFT_ASSIGN_CONVERT(t_scope, scope(), scope);
+ THRIFT_ASSIGN(path);
+ THRIFT_ASSIGN(out_path);
+ THRIFT_ASSIGN(name);
+ THRIFT_ASSIGN(include_prefix);
+ THRIFT_ASSIGN(cpp_includes);
+ THRIFT_ASSIGN(c_includes);
+ THRIFT_ASSIGN(namespaces);
+ THRIFT_ASSIGN_N(is_out_path_absolute(), out_path_is_absolute, );
+ THRIFT_ASSIGN_N(get_namespace(), namespace_, );
+ THRIFT_ASSIGN_LIST_ID(t_type, typedef);
+ THRIFT_ASSIGN_LIST_ID(t_type, enum);
+ THRIFT_ASSIGN_LIST_ID(t_type, object);
+ THRIFT_ASSIGN_LIST_ID(t_const, const);
+ THRIFT_ASSIGN_LIST_ID(t_service, service);
+ THRIFT_ASSIGN_LIST_N(t_program, get_includes(), includes);
+ to.program_id = reinterpret_cast<plugin::t_program_id>(from);
+}
+
+PluginDelegateResult delegateToPlugin(t_program* program, const std::string& options) {
+ std::string language;
+ std::map<std::string, std::string> parsed_options;
+ t_generator::parse_options(options, language, parsed_options);
+ std::string cmd = "thrift-gen-";
+ if (language.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-0123456789")
+ != std::string::npos) {
+ std::cerr << "Invalid language name" << std::endl;
+ return PLUGIN_FAILURE;
+ }
+ cmd.append(language);
+ FILE* fd = THRIFT_POPEN(cmd.c_str());
+ if (fd) {
+#ifdef _WIN32
+ _setmode(fileno(fd), _O_BINARY);
+#endif
+ boost::shared_ptr<TFramedTransport> transport(
+ new TFramedTransport(boost::make_shared<TFDTransport>(fileno(fd))));
+ TBinaryProtocol proto(transport);
+
+ plugin::GeneratorInput input;
+ input.__set_parsed_options(parsed_options);
+ clear_global_cache();
+ convert(program, input.program);
+ get_global_cache(input.type_registry);
+ try {
+ input.write(&proto);
+ transport->flush();
+ } catch (std::exception& err) {
+ std::cerr << "Error while sending data to plugin: " << err.what() << std::endl;
+ THRIFT_PCLOSE(fd);
+ return PLUGIN_FAILURE;
+ }
+
+ // TODO: be prepared for hang or crash of child process
+ int ret = THRIFT_PCLOSE(fd);
+ if (!ret) {
+ return PLUGIN_SUCCEESS;
+ } else {
+ std::cerr << "plugin process returned non zero exit code: " << ret << std::endl;
+ return PLUGIN_FAILURE;
+ }
+ }
+ clear_global_cache();
+ return PLUGIN_NOT_FOUND;
+}
+}
diff --git a/compiler/cpp/src/plugin/plugin_output.h b/compiler/cpp/src/plugin/plugin_output.h
new file mode 100644
index 000000000..eab2d1bfc
--- /dev/null
+++ b/compiler/cpp/src/plugin/plugin_output.h
@@ -0,0 +1,38 @@
+/*
+ * 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 T_PLUGIN_PLUGIN_OUTPUT_H
+#define T_PLUGIN_PLUGIN_OUTPUT_H
+
+#include <string>
+
+class t_program;
+
+namespace plugin_output {
+
+enum PluginDelegateResult {
+ PLUGIN_NOT_FOUND,
+ PLUGIN_FAILURE,
+ PLUGIN_SUCCEESS,
+};
+
+PluginDelegateResult delegateToPlugin(t_program* program, const std::string& options);
+}
+
+#endif
diff --git a/compiler/cpp/src/plugin/type_util.h b/compiler/cpp/src/plugin/type_util.h
new file mode 100644
index 000000000..508b74181
--- /dev/null
+++ b/compiler/cpp/src/plugin/type_util.h
@@ -0,0 +1,94 @@
+/*
+ * 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 T_PLUGIN_TYPE_UTIL_H
+#define T_PLUGIN_TYPE_UTIL_H
+
+namespace apache {
+namespace thrift {
+namespace plugin {
+
+template <typename From>
+struct ToType {};
+
+template <typename From>
+typename ToType<From>::type* convert_forward(const From&);
+
+template <typename From, typename To>
+void convert(const From&, To*);
+
+template <typename From>
+typename ToType<From>::type* convert(const From& from);
+
+class TypeRegistry;
+void set_global_cache(const TypeRegistry&);
+}
+}
+}
+
+// conversion from raw compiler types to plugin wire type
+namespace plugin_output {
+
+template <typename From, typename To>
+void convert(From* from, To& to);
+
+template <typename From>
+typename apache::thrift::plugin::ToType<From>::type convert(From* from);
+
+void get_global_cache(apache::thrift::plugin::TypeRegistry&);
+void clear_global_cache();
+}
+
+#define THRIFT_TYPE_MAPPING(TYPE) \
+ class TYPE; \
+ namespace apache { \
+ namespace thrift { \
+ namespace plugin { \
+ class TYPE; \
+ template <> \
+ struct ToType< ::TYPE> { \
+ typedef TYPE type; \
+ }; \
+ template <> \
+ struct ToType<TYPE> { \
+ typedef ::TYPE type; \
+ }; \
+ } \
+ } \
+ }
+THRIFT_TYPE_MAPPING(t_base_type)
+THRIFT_TYPE_MAPPING(t_const)
+THRIFT_TYPE_MAPPING(t_const_value)
+THRIFT_TYPE_MAPPING(t_container)
+THRIFT_TYPE_MAPPING(t_doc)
+THRIFT_TYPE_MAPPING(t_enum)
+THRIFT_TYPE_MAPPING(t_enum_value)
+THRIFT_TYPE_MAPPING(t_field)
+THRIFT_TYPE_MAPPING(t_function)
+THRIFT_TYPE_MAPPING(t_list)
+THRIFT_TYPE_MAPPING(t_map)
+THRIFT_TYPE_MAPPING(t_program)
+THRIFT_TYPE_MAPPING(t_scope)
+THRIFT_TYPE_MAPPING(t_service)
+THRIFT_TYPE_MAPPING(t_set)
+THRIFT_TYPE_MAPPING(t_struct)
+THRIFT_TYPE_MAPPING(t_type)
+THRIFT_TYPE_MAPPING(t_typedef)
+#undef THRIFT_TYPE_MAPPING
+#endif
diff --git a/compiler/cpp/src/thriftl.ll b/compiler/cpp/src/thriftl.ll
index 5c3187d96..f47928013 100644
--- a/compiler/cpp/src/thriftl.ll
+++ b/compiler/cpp/src/thriftl.ll
@@ -56,6 +56,7 @@
#include "windows/config.h"
#endif
#include "main.h"
+#include "common.h"
#include "globals.h"
#include "parse/t_program.h"
diff --git a/compiler/cpp/src/thrifty.yy b/compiler/cpp/src/thrifty.yy
index 292670d59..51de58f8e 100644
--- a/compiler/cpp/src/thrifty.yy
+++ b/compiler/cpp/src/thrifty.yy
@@ -38,6 +38,7 @@
#include "windows/config.h"
#endif
#include "main.h"
+#include "common.h"
#include "globals.h"
#include "parse/t_program.h"
#include "parse/t_scope.h"
diff --git a/compiler/cpp/version.h.in b/compiler/cpp/src/version.h.in
index 5770ec9b9..5770ec9b9 100644
--- a/compiler/cpp/version.h.in
+++ b/compiler/cpp/src/version.h.in
diff --git a/compiler/cpp/test/CMakeLists.txt b/compiler/cpp/test/CMakeLists.txt
new file mode 100644
index 000000000..047e23ec5
--- /dev/null
+++ b/compiler/cpp/test/CMakeLists.txt
@@ -0,0 +1,77 @@
+#
+# 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.
+#
+
+
+if(${WITH_PLUGIN})
+ include_directories(SYSTEM "${Boost_INCLUDE_DIRS}")
+
+ # Make sure gen-cpp files can be included
+ include_directories("${CMAKE_CURRENT_BINARY_DIR}")
+
+ set(plugintest_SOURCES
+ plugin/conversion_test.cc
+ )
+ add_executable(plugintest ${plugintest_SOURCES})
+ if(WITH_SHARED_LIB AND NOT MSVC)
+ target_link_libraries(plugintest
+ thriftc
+ ${Boost_LIBRARIES}
+ )
+ else()
+ target_link_libraries(plugintest
+ thriftc_static
+ thrift_static
+ ${Boost_LIBRARIES}
+ )
+ endif()
+ add_test(NAME PluginUnitTest COMMAND plugintest)
+
+ set(thrift-gen-mycpp_SOURCES
+ ../src/generate/t_cpp_generator.cc
+ plugin/cpp_plugin.cc
+ )
+ add_executable(thrift-gen-mycpp ${thrift-gen-mycpp_SOURCES})
+ if(WITH_SHARED_LIB AND NOT MSVC)
+ target_link_libraries(thrift-gen-mycpp thriftc)
+ else()
+ target_link_libraries(thrift-gen-mycpp thriftc_static thrift_static)
+ endif()
+
+ if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+ set(BUILDTYPE "Debug")
+ else()
+ # RelWithDebInfo generates binaries in "Release" directory too
+ set(BUILDTYPE "Release")
+ endif()
+
+ set_directory_properties(PROPERTIES
+ ADDITIONAL_MAKE_CLEAN_FILES gen-cpp
+ ADDITIONAL_MAKE_CLEAN_FILES gen-mycpp)
+
+ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp)
+ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/gen-mycpp)
+ add_test(NAME PluginIntegrationTest
+ COMMAND ${CMAKE_COMMAND}
+ -DTHRIFT_COMPILER=${THRIFT_COMPILER}
+ -DBINDIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
+ -DBUILDTYPE=${BUILDTYPE}
+ -DCURDIR=${CMAKE_CURRENT_BINARY_DIR}
+ -DSRCDIR=${CMAKE_CURRENT_SOURCE_DIR}
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/cpp_plugin_test.cmake)
+endif()
diff --git a/compiler/cpp/test/Makefile.am b/compiler/cpp/test/Makefile.am
new file mode 100644
index 000000000..5a232029a
--- /dev/null
+++ b/compiler/cpp/test/Makefile.am
@@ -0,0 +1,51 @@
+#
+# 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.
+#
+#
+# Contains some contributions under the Thrift Software License.
+# Please see doc/old-thrift-license.txt in the Thrift distribution for
+# details.
+
+AUTOMAKE_OPTIONS = subdir-objects serial-tests
+
+AM_CPPFLAGS = $(BOOST_CPPFLAGS) -I$(top_srcdir)/compiler/cpp/src
+AM_LDFLAGS = $(BOOST_LDFLAGS)
+AM_CXXFLAGS = -Wall -Wextra -pedantic
+
+if WITH_PLUGIN
+check_PROGRAMS = plugintest
+
+noinst_PROGRAMS = thrift-gen-mycpp
+
+AM_CPPFLAGS += -I$(top_srcdir)/lib/cpp/src -I$(top_builddir)/lib/cpp/src
+
+plugintest_SOURCES = plugin/conversion_test.cc
+plugintest_LDADD = $(top_builddir)/compiler/cpp/libthriftc.la
+
+thrift_gen_mycpp_SOURCES = plugin/cpp_plugin.cc \
+ plugin/t_cpp_generator.cc
+thrift_gen_mycpp_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/compiler/cpp -I$(top_srcdir)/compiler/cpp/src/generate
+thrift_gen_mycpp_LDADD = $(top_builddir)/compiler/cpp/libthriftc.la
+
+cpp_plugin_test.sh: thrift-gen-mycpp
+TESTS = $(check_PROGRAMS) cpp_plugin_test.sh
+
+clean-local:
+ $(RM) -rf gen-cpp gen-mycpp
+
+endif
diff --git a/compiler/cpp/test/cpp_plugin_test.cmake b/compiler/cpp/test/cpp_plugin_test.cmake
new file mode 100644
index 000000000..fd182818d
--- /dev/null
+++ b/compiler/cpp/test/cpp_plugin_test.cmake
@@ -0,0 +1,45 @@
+#
+# 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.
+#
+
+file(MAKE_DIRECTORY ${CURDIR}/gen-cpp)
+execute_process(COMMAND ${THRIFT_COMPILER} -r -out ${CURDIR}/gen-cpp -gen cpp ${SRCDIR}/../../../test/Include.thrift)
+if(EXITCODE)
+ message(FATAL_ERROR "FAILED: \"${ARGV}\": \"${EXITCODE}\"")
+endif()
+if(WIN32)
+ set(ENV{PATH} "${BINDIR}/${BUILDTYPE};${BINDIR};$ENV{PATH}")
+else()
+ set(ENV{PATH} "${BINDIR}:$ENV{PATH}")
+endif()
+
+file(MAKE_DIRECTORY ${CURDIR}/gen-mycpp)
+execute_process(COMMAND ${THRIFT_COMPILER} -r -out ${CURDIR}/gen-mycpp -gen mycpp ${SRCDIR}/../../../test/Include.thrift RESULT_VARIABLE EXITCODE)
+if(EXITCODE)
+ message(FATAL_ERROR "FAILED: \"${EXITCODE}\"")
+endif()
+
+find_program(DIFF diff)
+if(DIFF)
+ execute_process(COMMAND ${DIFF} -urN gen-cpp gen-mycpp RESULT_VARIABLE EXITCODE)
+ if(EXITCODE)
+ message(FATAL_ERROR "FAILED: \"${EXITCODE}\"")
+ endif()
+else()
+ message(WARNING "diff executable is not available. Not validating plugin-generated code.")
+endif()
diff --git a/compiler/cpp/test/cpp_plugin_test.sh b/compiler/cpp/test/cpp_plugin_test.sh
new file mode 100755
index 000000000..ddb2e0a09
--- /dev/null
+++ b/compiler/cpp/test/cpp_plugin_test.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+# this file is intended to be invoked by make.
+set -e
+mkdir -p gen-cpp gen-mycpp
+PATH=.:"$PATH" ../thrift -r -out gen-cpp -gen cpp ../../../test/Include.thrift
+PATH=.:"$PATH" ../thrift -r -out gen-mycpp -gen mycpp ../../../test/Include.thrift
+diff -urN gen-cpp gen-mycpp
diff --git a/compiler/cpp/test/plugin/conversion_test.cc b/compiler/cpp/test/plugin/conversion_test.cc
new file mode 100644
index 000000000..f2d140797
--- /dev/null
+++ b/compiler/cpp/test/plugin/conversion_test.cc
@@ -0,0 +1,496 @@
+/*
+ * 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.
+ */
+
+#include "parse/t_program.h"
+#include "plugin/type_util.h"
+#include "plugin/plugin_types.h"
+
+#include <map>
+#include <vector>
+
+#include <boost/preprocessor.hpp>
+#include <boost/test/included/unit_test.hpp>
+#include <boost/test/parameterized_test.hpp>
+
+using namespace apache::thrift;
+using namespace boost::unit_test;
+
+namespace test_data {
+#define T_TEST_TYPES \
+ BOOST_PP_TUPLE_TO_LIST(14, \
+ (program, \
+ base_type, \
+ enum_value, \
+ enum, \
+ const_value, \
+ const, \
+ list, \
+ set, \
+ map, \
+ field, \
+ struct, \
+ typedef, \
+ function, \
+ service))
+#define T_DELETE_TESTDATA(r, d, elem) \
+ for (std::vector<t_##elem*>::reverse_iterator it = elem##s.rbegin(); it != elem##s.rend(); it++) \
+ delete *it;
+#define T_DECL_TESTDATA(r, d, elem) static std::vector< ::t_##elem*> elem##s;
+BOOST_PP_LIST_FOR_EACH(T_DECL_TESTDATA, _, T_TEST_TYPES)
+#undef T_DECL_TESTDATA
+
+bool has_data = false;
+void cleanup() {
+ if (has_data) {
+ has_data = false;
+ BOOST_PP_LIST_FOR_EACH(T_DELETE_TESTDATA, _, T_TEST_TYPES)
+ }
+}
+
+void init_programs() {
+ programs.push_back(new t_program("prog path", "prog_name"));
+}
+
+void init_base_types() {
+ base_types.push_back(new ::t_base_type("name0", ::t_base_type::TYPE_VOID));
+ base_types.push_back(new ::t_base_type("name1", ::t_base_type::TYPE_STRING));
+ base_types.push_back(new ::t_base_type("name2", ::t_base_type::TYPE_BOOL));
+ base_types.push_back(new ::t_base_type("name3", ::t_base_type::TYPE_I8));
+ base_types.push_back(new ::t_base_type("name4", ::t_base_type::TYPE_I16));
+ base_types.push_back(new ::t_base_type("name5", ::t_base_type::TYPE_I32));
+ base_types.push_back(new ::t_base_type("name6", ::t_base_type::TYPE_I64));
+ base_types.push_back(new ::t_base_type("name7", ::t_base_type::TYPE_DOUBLE));
+}
+
+void init_const_values() {
+ const_values.push_back(new t_const_value(42));
+ const_values.push_back(new t_const_value("foo"));
+ {
+ t_const_value* x = new t_const_value;
+ x->set_double(3.1415);
+ const_values.push_back(x);
+ }
+ {
+ t_const_value* x = new t_const_value;
+ x->set_identifier("bar");
+ x->set_enum(enums[0]);
+ const_values.push_back(x);
+ }
+ {
+ t_const_value* x = new t_const_value;
+ x->set_map();
+ x->add_map(const_values[0], const_values[1]);
+ x->add_map(const_values[1], const_values[0]);
+ const_values.push_back(x);
+ }
+ {
+ t_const_value* x = new t_const_value;
+ x->set_list();
+ x->add_list(const_values[0]);
+ x->add_list(const_values[1]);
+ const_values.push_back(x);
+ }
+}
+
+void init_consts() {
+ // base_type/enum indexes for this and other tests are arbitrary
+ consts.push_back(new t_const(base_types[2], "aaa", const_values[0]));
+ consts.back()->set_doc("soem doc");
+ consts.push_back(new t_const(base_types[3], "bbb", const_values[1]));
+}
+
+void init_enum_values() {
+ enum_values.push_back(new t_enum_value("VAL1", 11));
+ enum_values.back()->set_doc("enum doc 1");
+ enum_values.back()->annotations_.insert(std::make_pair("anno1", "val1"));
+
+ enum_values.push_back(new t_enum_value("VAL2", 22));
+}
+
+void init_enums() {
+ enums.push_back(new t_enum(programs[0]));
+ enums.back()->set_doc("enum doc 1");
+ enums.back()->annotations_.insert(std::make_pair("anno1", "val1"));
+ enums.back()->set_name("fooo");
+ enums.back()->append(enum_values[0]);
+ enums.back()->append(enum_values[1]);
+}
+
+void init_lists() {
+ lists.push_back(new t_list(enums[0]));
+ lists.push_back(new t_list(base_types[5]));
+ lists.back()->set_cpp_name("list_cpp_name_1");
+}
+void init_sets() {
+ sets.push_back(new t_set(base_types[4]));
+ sets.push_back(new t_set(enums[0]));
+ sets.back()->set_cpp_name("set_cpp_name_1");
+}
+void init_maps() {
+ maps.push_back(new t_map(base_types[4], base_types[1]));
+ maps.push_back(new t_map(base_types[5], enums[0]));
+ maps.back()->set_cpp_name("map_cpp_name_1");
+}
+
+void init_typedefs() {
+ typedefs.push_back(new t_typedef(programs[0], base_types[3], "VAL1"));
+}
+void init_fields() {
+ fields.push_back(new t_field(base_types[1], "f1"));
+ fields.back()->set_reference(false);
+ fields.back()->set_req(t_field::T_OPTIONAL);
+ fields.push_back(new t_field(base_types[2], "f2", 9));
+ fields.back()->set_reference(true);
+ fields.push_back(new t_field(base_types[3], "f3", 11));
+ fields.back()->set_req(t_field::T_REQUIRED);
+ fields.back()->set_value(const_values[0]);
+}
+void init_structs() {
+ structs.push_back(new t_struct(programs[0], "struct1"));
+ structs.back()->append(fields[0]);
+ structs.back()->append(fields[1]);
+ structs.push_back(new t_struct(programs[0], "union1"));
+ structs.back()->append(fields[0]);
+ structs.back()->append(fields[1]);
+ structs.back()->set_union(true);
+ structs.push_back(new t_struct(programs[0], "xcept1"));
+ structs.back()->set_xception(true);
+}
+void init_functions() {
+ structs.push_back(new t_struct(programs[0], "errs1"));
+ t_struct* errors = structs.back();
+ structs.push_back(new t_struct(programs[0], "args1"));
+ t_struct* arglist = structs.back();
+ functions.push_back(new t_function(base_types[0], "func1", errors, arglist, false));
+ functions.push_back(new t_function(base_types[0], "func2", errors, arglist, true));
+}
+void init_services() {
+ services.push_back(new t_service(programs[0]));
+ services.back()->set_doc("srv1 doc");
+ services.back()->set_name("srv1");
+ services.back()->add_function(functions[0]);
+ services.back()->add_function(functions[1]);
+
+ services.push_back(new t_service(programs[0]));
+ services.back()->set_name("srv2");
+ services.back()->set_extends(services[0]);
+}
+
+std::vector<t_type*> types;
+void init_types() {
+#define T_COPY_TYPES(type) std::copy(type##s.begin(), type##s.end(), std::back_inserter(types))
+ T_COPY_TYPES(base_type);
+ T_COPY_TYPES(enum);
+ T_COPY_TYPES(typedef);
+ T_COPY_TYPES(struct);
+ T_COPY_TYPES(list);
+ T_COPY_TYPES(set);
+ T_COPY_TYPES(map);
+// T_COPY_TYPES(service);
+#undef T_COPY_TYPES
+}
+
+void init() {
+ if (!has_data) {
+ has_data = true;
+#define T_INIT_TESTDATA(r, d, elem) init_##elem##s();
+ BOOST_PP_LIST_FOR_EACH(T_INIT_TESTDATA, _, T_TEST_TYPES)
+ init_types();
+#undef T_INIT_TESTDATA
+ }
+}
+}
+struct GlobalFixture {
+ ~GlobalFixture() { test_data::cleanup(); }
+};
+#if (BOOST_VERSION >= 105900)
+BOOST_GLOBAL_FIXTURE(GlobalFixture);
+#else
+BOOST_GLOBAL_FIXTURE(GlobalFixture)
+#endif
+
+void migrate_global_cache() {
+ plugin::TypeRegistry reg;
+ plugin_output::get_global_cache(reg);
+ plugin::set_global_cache(reg);
+ plugin_output::clear_global_cache();
+}
+template <typename T>
+T* round_trip(T* t) {
+ typename plugin::ToType<T>::type p;
+ plugin_output::convert(t, p);
+ migrate_global_cache();
+ return plugin::convert(p);
+}
+
+void test_base_type(::t_base_type* sut) {
+ plugin::t_base_type p;
+ plugin_output::convert(sut, p);
+ boost::scoped_ptr< ::t_base_type> sut2(plugin::convert(p));
+
+#define THRIFT_CHECK(r, data, elem) BOOST_PP_EXPAND(BOOST_CHECK_EQUAL(data elem, sut2->elem));
+ BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+ sut->,
+ BOOST_PP_TUPLE_TO_LIST(7,
+ (is_void(),
+ is_string(),
+ is_bool(),
+ is_string_list(),
+ is_binary(),
+ is_string_enum(),
+ is_base_type())))
+}
+
+void test_const_value(t_const_value* sut) {
+ boost::scoped_ptr<t_const_value> sut2(round_trip(sut));
+
+ BOOST_CHECK_EQUAL(sut->get_type(), sut2->get_type());
+ switch (sut->get_type()) {
+#define T_CONST_VALUE_CASE(type, name) \
+ case t_const_value::type: \
+ BOOST_CHECK_EQUAL(sut->get_##name(), sut2->get_##name()); \
+ break
+ T_CONST_VALUE_CASE(CV_INTEGER, integer);
+ T_CONST_VALUE_CASE(CV_DOUBLE, double);
+ T_CONST_VALUE_CASE(CV_STRING, string);
+ T_CONST_VALUE_CASE(CV_IDENTIFIER, identifier);
+#undef T_CONST_VALUE_CASE
+ case t_const_value::CV_MAP:
+ BOOST_CHECK_EQUAL(sut->get_map().size(), sut2->get_map().size());
+ {
+ std::map<t_const_value::t_const_value_type, t_const_value::t_const_value_type> sut_values;
+ for (std::map<t_const_value*, t_const_value*>::const_iterator it = sut->get_map().begin();
+ it != sut->get_map().end(); it++) {
+ sut_values[it->first->get_type()] = it->second->get_type();
+ }
+ std::map<t_const_value::t_const_value_type, t_const_value::t_const_value_type> sut2_values;
+ for (std::map<t_const_value*, t_const_value*>::const_iterator it = sut2->get_map().begin();
+ it != sut2->get_map().end(); it++) {
+ sut2_values[it->first->get_type()] = it->second->get_type();
+ }
+ BOOST_CHECK_EQUAL(sut_values.begin()->first, sut2_values.begin()->first);
+ BOOST_CHECK_EQUAL(sut_values.begin()->second, sut2_values.begin()->second);
+ }
+ break;
+ case t_const_value::CV_LIST:
+ BOOST_CHECK_EQUAL(sut->get_list().size(), sut2->get_list().size());
+ BOOST_CHECK_EQUAL(sut->get_list().front()->get_type(), sut2->get_list().front()->get_type());
+ break;
+ default:
+ BOOST_ASSERT(false);
+ break;
+ }
+}
+
+void test_const(t_const* sut) {
+ boost::scoped_ptr< ::t_const> sut2(round_trip(sut));
+
+ BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+ sut->,
+ BOOST_PP_TUPLE_TO_LIST(4,
+ (get_type()->get_name(),
+ get_name(),
+ get_value()->get_type(),
+ get_doc())))
+}
+
+void test_enum_value(t_enum_value* sut) {
+ boost::scoped_ptr<t_enum_value> sut2(round_trip(sut));
+
+ BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+ sut->,
+ BOOST_PP_TUPLE_TO_LIST(3, (get_name(), get_value(), get_doc())))
+}
+
+void test_enum(t_enum* sut) {
+ boost::scoped_ptr< ::t_enum> sut2(round_trip(sut));
+
+ BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+ sut->,
+ BOOST_PP_TUPLE_TO_LIST(6,
+ (get_name(),
+ get_min_value()->get_value(),
+ get_max_value()->get_value(),
+ get_constant_by_value(11)->get_value(),
+ get_constant_by_name("VAL1")->get_value(),
+ get_doc())))
+}
+
+void test_list(t_list* sut) {
+ boost::scoped_ptr<t_list> sut2(round_trip(sut));
+
+ BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+ sut->,
+ BOOST_PP_TUPLE_TO_LIST(4,
+ (get_elem_type()->get_name(),
+ has_cpp_name(),
+ get_doc(),
+ get_name())))
+ if (sut->has_cpp_name())
+ BOOST_CHECK_EQUAL(sut->get_cpp_name(), sut2->get_cpp_name());
+}
+void test_set(t_set* sut) {
+ boost::scoped_ptr<t_set> sut2(round_trip(sut));
+
+ BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+ sut->,
+ BOOST_PP_TUPLE_TO_LIST(4,
+ (get_elem_type()->get_name(),
+ has_cpp_name(),
+ get_doc(),
+ get_name())))
+ if (sut->has_cpp_name())
+ BOOST_CHECK_EQUAL(sut->get_cpp_name(), sut2->get_cpp_name());
+}
+void test_map(t_map* sut) {
+ boost::scoped_ptr<t_map> sut2(round_trip(sut));
+
+ BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+ sut->,
+ BOOST_PP_TUPLE_TO_LIST(5,
+ (get_key_type()->get_name(),
+ get_val_type()->get_name(),
+ has_cpp_name(),
+ get_doc(),
+ get_name())))
+ if (sut->has_cpp_name())
+ BOOST_CHECK_EQUAL(sut->get_cpp_name(), sut2->get_cpp_name());
+}
+
+void test_typedef(t_typedef* sut) {
+ boost::scoped_ptr<t_typedef> sut2(round_trip(sut));
+
+ BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+ sut->,
+ BOOST_PP_TUPLE_TO_LIST(4,
+ (get_doc(),
+ get_name(),
+ get_symbolic(),
+ is_forward_typedef())))
+}
+
+void test_type(t_type* sut) {
+ boost::scoped_ptr<t_type> sut2(round_trip(sut));
+
+ BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+ sut->,
+ BOOST_PP_TUPLE_TO_LIST(15,
+ (is_void(),
+ is_base_type(),
+ is_string(),
+ is_bool(),
+ is_typedef(),
+ is_enum(),
+ is_struct(),
+ is_xception(),
+ is_container(),
+ is_list(),
+ is_set(),
+ is_map(),
+ is_service(),
+ get_doc(),
+ get_name())))
+}
+
+void test_field(t_field* sut) {
+ boost::scoped_ptr<t_field> sut2(round_trip(sut));
+
+ BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+ sut->,
+ BOOST_PP_TUPLE_TO_LIST(5,
+ (get_req(),
+ get_reference(),
+ get_key(),
+ get_doc(),
+ get_name())))
+ if (sut->get_value()) {
+ THRIFT_CHECK(, sut->, get_value()->get_type());
+ } else {
+ BOOST_CHECK(!sut2->get_value());
+ }
+ if (sut->get_type()) {
+ THRIFT_CHECK(, sut->, get_type()->get_name());
+ } else {
+ BOOST_CHECK(!sut2->get_type());
+ }
+}
+void test_struct(t_struct* sut) {
+ boost::scoped_ptr<t_struct> sut2(round_trip(sut));
+
+ BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+ sut->,
+ BOOST_PP_TUPLE_TO_LIST(5,
+ (is_union(),
+ is_xception(),
+ is_struct(),
+ get_doc(),
+ get_name())))
+}
+
+void test_function(t_function* sut) {
+ boost::scoped_ptr<t_function> sut2(round_trip(sut));
+
+ BOOST_PP_LIST_FOR_EACH(
+ THRIFT_CHECK,
+ sut->,
+ BOOST_PP_TUPLE_TO_LIST(4, (get_doc(), get_name(), get_returntype()->get_name(), is_oneway())))
+}
+void test_service(t_service* sut) {
+ boost::scoped_ptr<t_service> sut2(round_trip(sut));
+
+ BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+ sut->,
+ BOOST_PP_TUPLE_TO_LIST(3, (get_doc(), get_name(), get_functions().size())))
+ if (sut->get_extends()) {
+ THRIFT_CHECK(, sut->, get_extends()->get_name());
+ } else {
+ BOOST_CHECK(!sut2->get_extends());
+ }
+}
+
+void test_program(t_program* sut) {
+ boost::scoped_ptr<t_program> sut2(round_trip(sut));
+
+ BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK, sut->, BOOST_PP_TUPLE_TO_LIST(2, (get_doc(), get_name())))
+}
+boost::unit_test::test_suite* do_init_unit_test_suite() {
+ test_data::init();
+ test_suite* ts = BOOST_TEST_SUITE("PluginConversionTest");
+
+#define T_TEST_CASE(r, d, type) \
+ ts->add(BOOST_PARAM_TEST_CASE(test_##type, test_data::type##s.begin(), test_data::type##s.end()));
+ BOOST_PP_LIST_FOR_EACH(T_TEST_CASE, _, T_TEST_TYPES)
+ T_TEST_CASE(_, _, type)
+#undef T_TEST_CASE
+ return ts;
+}
+
+#ifdef BOOST_TEST_DYN_LINK
+bool init_unit_test_suite() {
+ framework::master_test_suite().add(do_init_unit_test_suite());
+ return true;
+}
+int main(int argc, char* argv[]) {
+ return ::boost::unit_test::unit_test_main(&init_unit_test_suite, argc, argv);
+}
+#else
+boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) {
+ return do_init_unit_test_suite();
+}
+#endif
diff --git a/compiler/cpp/test/plugin/cpp_plugin.cc b/compiler/cpp/test/plugin/cpp_plugin.cc
new file mode 100644
index 000000000..43a62d4a8
--- /dev/null
+++ b/compiler/cpp/test/plugin/cpp_plugin.cc
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#include "plugin/plugin.h"
+#include "generate/t_generator.h"
+
+namespace apache {
+namespace thrift {
+namespace plugin {
+
+class MyCppGenerator : public GeneratorPlugin {
+ virtual int generate(::t_program* program,
+ const std::map<std::string, std::string>& parsed_options) {
+ t_generator* gen = t_generator_registry::get_generator(program, "cpp", parsed_options, "");
+ gen->generate_program();
+ delete gen;
+ return 0;
+ }
+};
+}
+}
+}
+
+int main(int argc, char* argv[]) {
+ apache::thrift::plugin::MyCppGenerator p;
+ return p.exec(argc, argv);
+}
diff --git a/configure.ac b/configure.ac
index b79094c7b..e11636f95 100755
--- a/configure.ac
+++ b/configure.ac
@@ -516,6 +516,22 @@ if test "$enable_tests" = "no"; then
fi
AM_CONDITIONAL(WITH_TESTS, [test "$have_tests" = "yes"])
+AC_ARG_ENABLE([plugin],
+ AS_HELP_STRING([--enable-plugin], [build compiler plugin support [default=yes]]),
+ [], enable_plugin=yes
+)
+have_plugin=yes
+if test "$have_cpp" = "no" ; then
+ have_plugin="no"
+fi
+if test "$enable_plugin" = "no"; then
+ have_plugin="no"
+fi
+if test "$have_plugin" = "yes" ; then
+ AC_CONFIG_LINKS([compiler/cpp/test/plugin/t_cpp_generator.cc:compiler/cpp/src/generate/t_cpp_generator.cc])
+fi
+AM_CONDITIONAL(WITH_PLUGIN, [test "$have_plugin" = "yes"])
+
AC_ARG_ENABLE([tutorial],
AS_HELP_STRING([--enable-tutorial], [build tutorial [default=yes]]),
[], enable_tutorial=yes
@@ -712,7 +728,10 @@ AH_BOTTOM([
AC_CONFIG_FILES([
Makefile
compiler/cpp/Makefile
- compiler/cpp/version.h
+ compiler/cpp/src/Makefile
+ compiler/cpp/src/plugin/Makefile
+ compiler/cpp/test/Makefile
+ compiler/cpp/src/version.h
compiler/cpp/src/windows/version.h
lib/Makefile
lib/cpp/Makefile
@@ -823,6 +842,7 @@ AC_OUTPUT
echo
echo "$PACKAGE $VERSION"
echo
+echo "Building Plugin Support ...... : $have_plugin"
echo "Building C++ Library ......... : $have_cpp"
echo "Building C (GLib) Library .... : $have_c_glib"
echo "Building Java Library ........ : $have_java"
diff --git a/debian/rules b/debian/rules
index a31881d77..84cba1f10 100755
--- a/debian/rules
+++ b/debian/rules
@@ -42,12 +42,12 @@ build: build-arch build-indep
build-arch: build-arch-stamp
$(CURDIR)/compiler/cpp/thrift build-arch-stamp: configure-stamp
- # Compile compiler
- $(MAKE) -C $(CURDIR)/compiler/cpp
-
# Compile C++ library
$(MAKE) -C $(CURDIR)/lib/cpp
+ # Compile compiler
+ $(MAKE) -C $(CURDIR)/compiler/cpp
+
# Compile C (glib) library
$(MAKE) -C $(CURDIR)/lib/c_glib
diff --git a/lib/Makefile.am b/lib/Makefile.am
index f12e09219..5f17fca88 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -21,8 +21,11 @@ SUBDIRS = json xml
PRECROSS_TARGET =
if WITH_CPP
+# cpp dir is picked directly by plugin build
+if !WITH_PLUGIN
SUBDIRS += cpp
endif
+endif
if WITH_C_GLIB
SUBDIRS += c_glib
diff --git a/lib/c_glib/test/CMakeLists.txt b/lib/c_glib/test/CMakeLists.txt
index 45ef41f3c..2c87dbcc9 100644
--- a/lib/c_glib/test/CMakeLists.txt
+++ b/lib/c_glib/test/CMakeLists.txt
@@ -18,12 +18,12 @@
#
-#Make sure gen-cpp and gen-c_glib files can be included
-include_directories("${CMAKE_CURRENT_BINARY_DIR}")
-
set(TEST_PREFIX "c_glib")
-include_directories(${Boost_INCLUDE_DIRS})
+include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
+
+#Make sure gen-cpp and gen-c_glib files can be included
+include_directories("${CMAKE_CURRENT_BINARY_DIR}")
# Create the thrift C test library
set(testgenc_SOURCES
diff --git a/lib/cpp/CMakeLists.txt b/lib/cpp/CMakeLists.txt
index 33cefcb1b..d07b4008c 100755
--- a/lib/cpp/CMakeLists.txt
+++ b/lib/cpp/CMakeLists.txt
@@ -17,13 +17,6 @@
# under the License.
#
-# Find required packages
-if(WITH_BOOSTTHREADS)
- find_package(Boost 1.53.0 REQUIRED COMPONENTS system thread)
-else()
- find_package(Boost 1.53.0 REQUIRED)
-endif()
-
include_directories(SYSTEM "${Boost_INCLUDE_DIRS}")
include_directories(src)
diff --git a/lib/cpp/Makefile.am b/lib/cpp/Makefile.am
index 6fd15d26e..2a1cca8ae 100755
--- a/lib/cpp/Makefile.am
+++ b/lib/cpp/Makefile.am
@@ -28,8 +28,12 @@ moc__%.cpp: %.h
SUBDIRS = .
if WITH_TESTS
+# This file is needed by compiler with plugin, while test/Makefile.am needs compiler
+# So test directory is directly picked by top level Makefile.am for plugin build
+if !WITH_PLUGIN
SUBDIRS += test
endif
+endif
pkgconfigdir = $(libdir)/pkgconfig
diff --git a/lib/cpp/src/thrift/protocol/TJSONProtocol.cpp b/lib/cpp/src/thrift/protocol/TJSONProtocol.cpp
index c46cc142a..d3ec72286 100644
--- a/lib/cpp/src/thrift/protocol/TJSONProtocol.cpp
+++ b/lib/cpp/src/thrift/protocol/TJSONProtocol.cpp
@@ -524,7 +524,7 @@ namespace {
std::string doubleToString(double d) {
std::ostringstream str;
str.imbue(std::locale::classic());
- const double max_digits10 = 2 + std::numeric_limits<double>::digits10;
+ const int max_digits10 = 2 + std::numeric_limits<double>::digits10;
str.precision(max_digits10);
str << d;
return str.str();
diff --git a/lib/cpp/src/thrift/protocol/TProtocol.h b/lib/cpp/src/thrift/protocol/TProtocol.h
index 1b46faf32..448c4fe5a 100644
--- a/lib/cpp/src/thrift/protocol/TProtocol.h
+++ b/lib/cpp/src/thrift/protocol/TProtocol.h
@@ -20,6 +20,11 @@
#ifndef _THRIFT_PROTOCOL_TPROTOCOL_H_
#define _THRIFT_PROTOCOL_TPROTOCOL_H_ 1
+#ifdef _WIN32
+// Need to come before any Windows.h includes
+#include <Winsock2.h>
+#endif
+
#include <thrift/transport/TTransport.h>
#include <thrift/protocol/TProtocolException.h>
diff --git a/lib/cpp/src/thrift/windows/GetTimeOfDay.cpp b/lib/cpp/src/thrift/windows/GetTimeOfDay.cpp
index fba077c95..820828f32 100644
--- a/lib/cpp/src/thrift/windows/GetTimeOfDay.cpp
+++ b/lib/cpp/src/thrift/windows/GetTimeOfDay.cpp
@@ -21,8 +21,6 @@
#include <thrift/thrift-config.h>
// win32
-#include <time.h>
-
#if defined(__MINGW32__)
#include <sys/time.h>
#endif
diff --git a/lib/cpp/src/thrift/windows/GetTimeOfDay.h b/lib/cpp/src/thrift/windows/GetTimeOfDay.h
index 6e90ba183..762ac5e24 100644
--- a/lib/cpp/src/thrift/windows/GetTimeOfDay.h
+++ b/lib/cpp/src/thrift/windows/GetTimeOfDay.h
@@ -29,6 +29,7 @@
#endif
#include <thrift/thrift-config.h>
+#include <time.h>
struct thrift_timespec {
int64_t tv_sec;
diff --git a/lib/cpp/src/thrift/windows/config.h b/lib/cpp/src/thrift/windows/config.h
index 108e05b29..8650103a8 100644
--- a/lib/cpp/src/thrift/windows/config.h
+++ b/lib/cpp/src/thrift/windows/config.h
@@ -30,6 +30,7 @@
// use std::thread in MSVC11 (2012) or newer
#if _MSC_VER >= 1700
+#define HAVE_STDINT_H 1
#define USE_STD_THREAD 1
// otherwise use boost threads
#else
diff --git a/lib/cpp/test/CMakeLists.txt b/lib/cpp/test/CMakeLists.txt
index 7c7e32071..cbeff0884 100644
--- a/lib/cpp/test/CMakeLists.txt
+++ b/lib/cpp/test/CMakeLists.txt
@@ -17,15 +17,8 @@
# under the License.
#
-# Find required packages
-set(Boost_USE_STATIC_LIBS ON) # Force the use of static boost test framework
-find_package(Boost 1.53.0 REQUIRED COMPONENTS chrono filesystem system thread unit_test_framework)
include_directories(SYSTEM "${Boost_INCLUDE_DIRS}")
-if (WITH_DYN_LINK_TEST)
- add_definitions( -DBOOST_TEST_DYN_LINK )
-endif()
-
#Make sure gen-cpp files can be included
include_directories("${CMAKE_CURRENT_BINARY_DIR}")
diff --git a/lib/cpp/test/Makefile.am b/lib/cpp/test/Makefile.am
index 4e76ce8b4..6f4611745 100755
--- a/lib/cpp/test/Makefile.am
+++ b/lib/cpp/test/Makefile.am
@@ -358,7 +358,7 @@ gen-cpp/SecondService.cpp gen-cpp/ThriftTest_constants.cpp gen-cpp/ThriftTest.cp
gen-cpp/ChildService.cpp gen-cpp/ChildService.h gen-cpp/ParentService.cpp gen-cpp/ParentService.h gen-cpp/proc_types.cpp gen-cpp/proc_types.h: processor/proc.thrift
$(THRIFT) --gen cpp:templates,cob_style $<
-AM_CPPFLAGS = $(BOOST_CPPFLAGS) -I$(top_srcdir)/lib/cpp/src -D__STDC_LIMIT_MACROS
+AM_CPPFLAGS = $(BOOST_CPPFLAGS) -I$(top_srcdir)/lib/cpp/src -D__STDC_LIMIT_MACROS -I.
AM_LDFLAGS = $(BOOST_LDFLAGS)
AM_CXXFLAGS = -Wall -Wextra -pedantic
diff --git a/test/cpp/CMakeLists.txt b/test/cpp/CMakeLists.txt
index 11db68ee8..09850a814 100755
--- a/test/cpp/CMakeLists.txt
+++ b/test/cpp/CMakeLists.txt
@@ -20,8 +20,6 @@
# Contains the thrift specific LINK_AGAINST_THRIFT_LIBRARY
include(ThriftMacros)
-set(Boost_USE_STATIC_LIBS ON)
-find_package(Boost 1.53.0 REQUIRED COMPONENTS program_options system filesystem)
include_directories(SYSTEM "${Boost_INCLUDE_DIRS}")
find_package(OpenSSL REQUIRED)
diff --git a/tutorial/cpp/CMakeLists.txt b/tutorial/cpp/CMakeLists.txt
index 8a3d08551..1feec2c35 100644
--- a/tutorial/cpp/CMakeLists.txt
+++ b/tutorial/cpp/CMakeLists.txt
@@ -17,7 +17,6 @@
# under the License.
#
-find_package(Boost 1.53.0 REQUIRED)
include_directories(SYSTEM "${Boost_INCLUDE_DIRS}")
#Make sure gen-cpp files can be included
@@ -27,7 +26,7 @@ include_directories("${PROJECT_SOURCE_DIR}/lib/cpp/src")
include(ThriftMacros)
-set(tutorialgencpp_SOURCES
+set(tutorialgencpp_SOURCES
gen-cpp/Calculator.cpp
gen-cpp/SharedService.cpp
gen-cpp/shared_constants.cpp