diff --git a/paddle/CMakeLists.txt b/paddle/CMakeLists.txt index 503024cff338dac42a6a8a32463472dc6b6451d9..b3f3b2fbcedd78a2d19d1b29ac416680cb060208 100644 --- a/paddle/CMakeLists.txt +++ b/paddle/CMakeLists.txt @@ -8,7 +8,7 @@ add_subdirectory(gserver) add_subdirectory(pserver) add_subdirectory(trainer) add_subdirectory(scripts) - +add_subdirectory(capi) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in ${CMAKE_CURRENT_SOURCE_DIR}/setup.py) diff --git a/paddle/capi/Arguments.cpp b/paddle/capi/Arguments.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cf773a65872fc3c0136994892197599558934da4 --- /dev/null +++ b/paddle/capi/Arguments.cpp @@ -0,0 +1,49 @@ +#include "PaddleCAPI.h" +#include "PaddleCAPIPrivate.h" + +#define cast(v) paddle::capi::cast(v) + +extern "C" { +int PDArgsCreateNone(PD_Arguments* args) { + auto ptr = new paddle::capi::CArguments(); + *args = ptr; + return PD_NO_ERROR; +} + +int PDArgsDestroy(PD_Arguments args) { + if (args == nullptr) return PD_NULLPTR; + delete cast(args); + return PD_NO_ERROR; +} + +int PDArgsGetSize(PD_Arguments args, uint64_t* size) { + if (args == nullptr || size == nullptr) return PD_NULLPTR; + *size = cast(args)->args.size(); + return PD_NO_ERROR; +} + +int PDArgsResize(PD_Arguments args, uint64_t size) { + if (args == nullptr) return PD_NULLPTR; + cast(args)->args.resize(size); + return PD_NO_ERROR; +} + +int PDArgsSetValue(PD_Arguments args, uint64_t ID, PD_Matrix mat) { + if (args == nullptr || mat == nullptr) return PD_NULLPTR; + auto m = paddle::capi::cast(mat); + if (m->mat == nullptr) return PD_NULLPTR; + auto a = cast(args); + if (ID >= a->args.size()) return PD_OUT_OF_RANGE; + a->args[ID].value = m->mat; + return PD_NO_ERROR; +} + +int PDArgsGetValue(PD_Arguments args, uint64_t ID, PD_Matrix mat) { + if (args == nullptr || mat == nullptr) return PD_NULLPTR; + auto m = paddle::capi::cast(mat); + auto a = cast(args); + if (ID >= a->args.size()) return PD_OUT_OF_RANGE; + m->mat = a->args[ID].value; + return PD_NO_ERROR; +} +} diff --git a/paddle/capi/CMakeLists.txt b/paddle/capi/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..6162267dab7cd2793262a3e217e488b5692acca6 --- /dev/null +++ b/paddle/capi/CMakeLists.txt @@ -0,0 +1,47 @@ +if (WITH_DOUBLE) + set(PADDLE_FLOAT_TYPE double) +else () + set(PADDLE_FLOAT_TYPE float) +endif() + +configure_file(config.h.in config.h @ONLY) + +set(CAPI_HEADER + PaddleCAPI.h) +set(CAPI_PRIVATE_HEADER + PaddleCAPIPrivate.h) +file(GLOB CAPI_SOURCES *.cpp) + +add_library(paddle_capi SHARED ${CAPI_SOURCES}) + +target_include_directories(paddle_capi PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) +add_dependencies(paddle_capi gen_proto_cpp) + +target_link_libraries(paddle_capi + paddle_gserver + paddle_function + paddle_pserver + paddle_trainer_lib + paddle_network + paddle_math + paddle_utils + paddle_parameter + paddle_proto + paddle_cuda + ${PROTOBUF_LIBRARY} + ${LIBGLOG_LIBRARY} + ${GFLAGS_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} + ${CBLAS_LIBS} + ${ZLIB_LIBRARIES} + ${INTERAL_LIBS} + ${CMAKE_DL_LIBS}) + + +set(PADDLE_CAPI_INC_PATH + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}) + +if (WITH_TESTING) + add_subdirectory(tests) +endif() diff --git a/paddle/capi/Matrix.cpp b/paddle/capi/Matrix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..71598b1714d1986109635e901ef7ce574ddb0946 --- /dev/null +++ b/paddle/capi/Matrix.cpp @@ -0,0 +1,61 @@ +#include "PaddleCAPI.h" +#include "PaddleCAPIPrivate.h" +#include "hl_cuda.h" + +#define cast(v) paddle::capi::cast(v) +extern "C" { +int PDMatCreate(PD_Matrix* mat, uint64_t height, uint64_t width, bool useGpu) { + auto ptr = new paddle::capi::CMatrix(); + ptr->mat = paddle::Matrix::create(height, width, false, useGpu); + *mat = ptr; + return PD_NO_ERROR; +} + +int PDMatCreateNone(PD_Matrix* mat) { + auto ptr = new paddle::capi::CMatrix(); + *mat = ptr; + return PD_NO_ERROR; +} + +int PDMatDestroy(PD_Matrix mat) { + if (mat == nullptr) return PD_NULLPTR; + auto ptr = cast(mat); + delete ptr; + return PD_NO_ERROR; +} + +int PDMatCopyToRow(PD_Matrix mat, uint64_t rowID, pd_real* rowArray) { + if (mat == nullptr) return PD_NULLPTR; + auto ptr = cast(mat); + if (ptr->mat == nullptr) return PD_NULLPTR; + if (rowID >= ptr->mat->getHeight()) return PD_OUT_OF_RANGE; + paddle::real* buf = ptr->mat->getRowBuf(rowID); + size_t width = ptr->mat->getWidth(); +#ifndef PADDLE_ONLY_CPU + hl_memcpy(buf, rowArray, sizeof(paddle::real) * width); +#else + std::copy(rowArray, rowArray + width, buf); +#endif + return PD_NO_ERROR; +} + +int PDMatGetRow(PD_Matrix mat, uint64_t rowID, pd_real** rawRowBuffer) { + if (mat == nullptr) return PD_NULLPTR; + auto ptr = cast(mat); + if (ptr->mat == nullptr) return PD_NULLPTR; + if (rowID >= ptr->mat->getHeight()) return PD_OUT_OF_RANGE; + *rawRowBuffer = ptr->mat->getRowBuf(rowID); + return PD_NO_ERROR; +} + +int PDMatGetShape(PD_Matrix mat, uint64_t* height, uint64_t* width) { + if (mat == nullptr) return PD_NULLPTR; + if (height != nullptr) { + *height = cast(mat)->mat->getHeight(); + } + if (width != nullptr) { + *width = cast(mat)->mat->getWidth(); + } + return PD_NO_ERROR; +} +} diff --git a/paddle/capi/PaddleCAPI.h b/paddle/capi/PaddleCAPI.h new file mode 100644 index 0000000000000000000000000000000000000000..2eff0bc7da25c5e3490a0c2bd84ca0249c544e39 --- /dev/null +++ b/paddle/capi/PaddleCAPI.h @@ -0,0 +1,54 @@ +#ifndef __PADDLE_PADDLE_CAPI_PADDLECAPI_H_INCLUDED__ +#define __PADDLE_PADDLE_CAPI_PADDLECAPI_H_INCLUDED__ +#include +#include +#include "config.h" +#ifdef __cplusplus +extern "C" { +#endif + +#define PD_NO_ERROR 0 +#define PD_NULLPTR 1 +#define PD_OUT_OF_RANGE 2 +#define PD_UNDEFINED_ERROR -1 + +typedef void* PD_Vector; + +int PDVecCreate(PD_Vector* vec, uint64_t size, bool useGpu); + +int PDVecDestroy(PD_Vector vec); + +int PDVecIsSparse(PD_Vector vec, bool* isSparse); + +typedef void* PD_Matrix; + +int PDMatCreate(PD_Matrix* mat, uint64_t height, uint64_t width, bool useGpu); + +int PDMatDestroy(PD_Matrix mat); + +int PDMatCopyToRow(PD_Matrix mat, uint64_t rowID, pd_real* rowArray); + +int PDMatGetRow(PD_Matrix mat, uint64_t rowID, pd_real** rawRowBuffer); + +int PDMatCreateNone(PD_Matrix* mat); + +int PDMatGetShape(PD_Matrix mat, uint64_t* height, uint64_t* width); + +typedef void* PD_Arguments; + +int PDArgsCreateNone(PD_Arguments* args); + +int PDArgsDestroy(PD_Arguments args); + +int PDArgsGetSize(PD_Arguments args, uint64_t* size); + +int PDArgsResize(PD_Arguments args, uint64_t size); + +int PDArgsSetValue(PD_Arguments args, uint64_t ID, PD_Matrix mat); + +int PDArgsGetValue(PD_Arguments args, uint64_t ID, PD_Matrix mat); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/paddle/capi/PaddleCAPIPrivate.h b/paddle/capi/PaddleCAPIPrivate.h new file mode 100644 index 0000000000000000000000000000000000000000..efec60fbb68ec4a4d63aad49594f136be1fcf517 --- /dev/null +++ b/paddle/capi/PaddleCAPIPrivate.h @@ -0,0 +1,27 @@ +#include "PaddleCAPI.h" +#include "paddle/math/Matrix.h" +#include "paddle/math/Vector.h" +#include "paddle/parameter/Argument.h" +#pragma once + +namespace paddle { +namespace capi { + +struct CVector { + VectorPtr vec; +}; + +struct CMatrix { + MatrixPtr mat; +}; + +struct CArguments { + std::vector args; +}; + +template +inline T* cast(void* ptr) { + return reinterpret_cast(ptr); +} +} +} diff --git a/paddle/capi/Vector.cpp b/paddle/capi/Vector.cpp new file mode 100644 index 0000000000000000000000000000000000000000..10dee7816c376eb7376d4fa50fc3b524c84a8f86 --- /dev/null +++ b/paddle/capi/Vector.cpp @@ -0,0 +1,26 @@ +#include "PaddleCAPI.h" +#include "PaddleCAPIPrivate.h" + +#define cast(v) paddle::capi::cast(v) +extern "C" { +int PDVecCreate(PD_Vector* vec, uint64_t size, bool useGpu) { + auto ptr = new paddle::capi::CVector(); + ptr->vec = paddle::Vector::create(size, useGpu); + *vec = ptr; + return PD_NO_ERROR; +} +int PDVecDestroy(PD_Vector vec) { + auto v = cast(vec); + v->vec.reset(); + delete v; + return PD_NO_ERROR; +} + +int PDVecIsSparse(PD_Vector vec, bool* isSparse) { + if (isSparse == nullptr || vec == nullptr) { + return PD_NULLPTR; + } + *isSparse = cast(vec)->vec->isSparse(); + return PD_NO_ERROR; +} +} diff --git a/paddle/capi/config.h.in b/paddle/capi/config.h.in new file mode 100644 index 0000000000000000000000000000000000000000..32d8a364e0eaaa896bc6bd2f19c1c7914870ba85 --- /dev/null +++ b/paddle/capi/config.h.in @@ -0,0 +1,6 @@ +#ifndef __PADDLE_PADDLE_CAPI_CONFIG_H_INCLUDED__ +#define __PADDLE_PADDLE_CAPI_CONFIG_H_INCLUDED__ + +typedef @PADDLE_FLOAT_TYPE@ pd_real; + +#endif diff --git a/paddle/capi/tests/CMakeLists.txt b/paddle/capi/tests/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..cd6b1d7c6271b13de404c3bd9df6585619fd1b67 --- /dev/null +++ b/paddle/capi/tests/CMakeLists.txt @@ -0,0 +1,15 @@ +function(add_capi_unittest TARGET_NAME) + add_executable( + ${TARGET_NAME} + ${ARGN}) + target_link_libraries( + ${TARGET_NAME} + paddle_capi + paddle_test_main + ${GTEST_LIBRARIES}) + target_include_directories(${TARGET_NAME} PUBLIC ${PADDLE_CAPI_INC_PATH}) + add_test(NAME ${TARGET_NAME} COMMAND ${TARGET_NAME}) +endfunction() + +add_capi_unittest(capi_test_mats test_Vector.cpp + test_Matrix.cpp test_Arguments.cpp) diff --git a/paddle/capi/tests/test_Arguments.cpp b/paddle/capi/tests/test_Arguments.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c74abd60d1b106c55fc145c0ac32c9d175d82623 --- /dev/null +++ b/paddle/capi/tests/test_Arguments.cpp @@ -0,0 +1,54 @@ +#include "PaddleCAPI.h" +#include "gtest/gtest.h" +#include "paddle/utils/ThreadLocal.h" + +static std::vector randomBuffer(size_t bufSize) { + auto& eng = paddle::ThreadLocalRandomEngine::get(); + std::uniform_real_distribution dist(-1.0, 1.0); + std::vector retv; + retv.reserve(bufSize); + for (size_t i = 0; i < bufSize; ++i) { + retv.push_back(dist(eng)); + } + return retv; +} + +TEST(CAPIArguments, create) { + PD_Arguments args; + ASSERT_EQ(PD_NO_ERROR, PDArgsCreateNone(&args)); + uint64_t size; + ASSERT_EQ(PD_NO_ERROR, PDArgsGetSize(args, &size)); + ASSERT_EQ(0UL, size); + ASSERT_EQ(PD_NO_ERROR, PDArgsDestroy(args)); +} + +TEST(CAPIArguments, value) { + PD_Arguments args; + ASSERT_EQ(PD_NO_ERROR, PDArgsCreateNone(&args)); + ASSERT_EQ(PD_NO_ERROR, PDArgsResize(args, 1)); + + PD_Matrix mat; + ASSERT_EQ(PD_NO_ERROR, PDMatCreate(&mat, 128, 64, false)); + for (size_t i = 0; i < 128; ++i) { + std::vector sampleBuf = randomBuffer(64); + PDMatCopyToRow(mat, i, sampleBuf.data()); + } + ASSERT_EQ(PD_NO_ERROR, PDArgsSetValue(args, 0, mat)); + + PD_Matrix val; + ASSERT_EQ(PD_NO_ERROR, PDMatCreateNone(&val)); + + ASSERT_EQ(PD_NO_ERROR, PDArgsGetValue(args, 0, val)); + + for (size_t i = 0; i < 128; ++i) { + pd_real* row1; + pd_real* row2; + + ASSERT_EQ(PD_NO_ERROR, PDMatGetRow(mat, i, &row1)); + ASSERT_EQ(PD_NO_ERROR, PDMatGetRow(val, i, &row2)); + ASSERT_EQ(row1, row2); + } + ASSERT_EQ(PD_NO_ERROR, PDMatDestroy(val)); + ASSERT_EQ(PD_NO_ERROR, PDMatDestroy(mat)); + ASSERT_EQ(PD_NO_ERROR, PDArgsDestroy(args)); +} diff --git a/paddle/capi/tests/test_Matrix.cpp b/paddle/capi/tests/test_Matrix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0f04a4683049abae270259d8928e7efccbc07879 --- /dev/null +++ b/paddle/capi/tests/test_Matrix.cpp @@ -0,0 +1,33 @@ +#include "PaddleCAPI.h" +#include "gtest/gtest.h" + +TEST(CAPIMatrix, create) { + PD_Matrix mat; + ASSERT_EQ(PD_NO_ERROR, PDMatCreate(&mat, 128, 32, false)); + std::vector sampleRow; + sampleRow.resize(32); + for (size_t i = 0; i < sampleRow.size(); ++i) { + sampleRow[i] = 1.0 / (i + 1.0); + } + ASSERT_EQ(PD_NO_ERROR, PDMatCopyToRow(mat, 0, sampleRow.data())); + ASSERT_EQ(PD_OUT_OF_RANGE, PDMatCopyToRow(mat, 128, sampleRow.data())); + + pd_real* arrayPtr; + + ASSERT_EQ(PD_NO_ERROR, PDMatGetRow(mat, 0, &arrayPtr)); + for (size_t i = 0; i < sampleRow.size(); ++i) { + ASSERT_NEAR(sampleRow[i], arrayPtr[i], 1e-5); + } + + uint64_t height, width; + ASSERT_EQ(PD_NO_ERROR, PDMatGetShape(mat, &height, &width)); + ASSERT_EQ(128, height); + ASSERT_EQ(32, width); + ASSERT_EQ(PD_NO_ERROR, PDMatDestroy(mat)); +} + +TEST(CAPIMatrix, createNone) { + PD_Matrix mat; + ASSERT_EQ(PD_NO_ERROR, PDMatCreateNone(&mat)); + ASSERT_EQ(PD_NO_ERROR, PDMatDestroy(mat)); +} diff --git a/paddle/capi/tests/test_Vector.cpp b/paddle/capi/tests/test_Vector.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dbb987d440a84d1d71a59ba4df5f3dafe055e68f --- /dev/null +++ b/paddle/capi/tests/test_Vector.cpp @@ -0,0 +1,11 @@ +#include "PaddleCAPI.h" +#include "gtest/gtest.h" + +TEST(CAPIVector, create) { + PD_Vector tmp; + ASSERT_EQ(PD_NO_ERROR, PDVecCreate(&tmp, 128, false)); + bool isSparse; + ASSERT_EQ(PD_NO_ERROR, PDVecIsSparse(tmp, &isSparse)); + ASSERT_FALSE(isSparse); + ASSERT_EQ(PD_NO_ERROR, PDVecDestroy(tmp)); +} diff --git a/paddle/utils/ForceLink.h b/paddle/utils/ForceLink.h new file mode 100644 index 0000000000000000000000000000000000000000..66005e2992e48ce6d2878e6a20cb1fb640ff0cc5 --- /dev/null +++ b/paddle/utils/ForceLink.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. + +Licensed 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. */ + +#pragma once + +/// Declare a force link file ID. It can be enabled by +/// `PADDLE_ENABLE_FORCE_LINK_FILE`. It is +/// +/// Example: +/// +/// In some_file.cpp +/// @code{cpp} +/// static paddle::InitFunction init([]{...}); +/// PADDLE_REGISTER_FORCE_LINK_FILE(some_file) +/// @endcode{cpp} +/// +/// In main.cpp +/// @code{cpp} +/// PADDLE_ENABLE_FORCE_LINK_FILE(some_file); +/// +/// int main() { +/// ... +/// } +/// @endcode{cpp} +/// +/// Then the InitFunction in some_file.cpp can be invoked. +#define PADDLE_REGISTER_FORCE_LINK_FILE(ID) \ + int __paddle_register_force_link_file_##ID##_method__() { return 0; } + +/// Enable a force link file. The file with ID's static variables could +/// be all initialized. +#define PADDLE_ENABLE_FORCE_LINK_FILE(ID) \ + extern int __paddle_register_force_link_file_##ID##_method__(); \ + static int __paddle_register_force_link_file_##ID##_handler__ = \ + __paddle_register_force_link_file_##ID##_method__(); diff --git a/paddle/utils/tests/CMakeLists.txt b/paddle/utils/tests/CMakeLists.txt index 26fafbd1ab3f2967b765b8bcb973fb745c0e6422..d9b018ebbb27e4f785eeb5ec09f4379d3dfccbb1 100644 --- a/paddle/utils/tests/CMakeLists.txt +++ b/paddle/utils/tests/CMakeLists.txt @@ -15,3 +15,11 @@ if(NOT APPLE) COMMAND ${PROJ_ROOT}/paddle/utils/tests/test_CustomStackTracePrint.sh WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) endif() + +add_library(test_class_registrar_lib STATIC + test_ClassRegistrarLib.cpp + test_ClassRegistrarGlobals.cpp) + +add_simple_unittest(test_ClassRegistrar) +target_link_libraries(test_ClassRegistrar + test_class_registrar_lib) diff --git a/paddle/utils/tests/test_ClassRegistrar.cpp b/paddle/utils/tests/test_ClassRegistrar.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c867045cb68b522f82b413e720b212908f1dec63 --- /dev/null +++ b/paddle/utils/tests/test_ClassRegistrar.cpp @@ -0,0 +1,27 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. + +Licensed 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 +#include +#include "test_ClassRegistrarLib.h" +// Enable link test_ClassRegistrarLib.cpp +PADDLE_ENABLE_FORCE_LINK_FILE(test_registrar); + +TEST(ClassRegistrar, test) { + std::vector types; + gTestRegistrar_.forEachType( + [&types](const std::string& tp) { types.push_back(tp); }); + ASSERT_EQ(1, types.size()); + ASSERT_EQ("test", types[0]); +} diff --git a/paddle/utils/tests/test_ClassRegistrarGlobals.cpp b/paddle/utils/tests/test_ClassRegistrarGlobals.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0f36da137f9b923858deb209ffc11bbf3ed861aa --- /dev/null +++ b/paddle/utils/tests/test_ClassRegistrarGlobals.cpp @@ -0,0 +1,16 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. + +Licensed 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 "test_ClassRegistrarLib.h" +paddle::ClassRegistrar gTestRegistrar_; diff --git a/paddle/utils/tests/test_ClassRegistrarLib.cpp b/paddle/utils/tests/test_ClassRegistrarLib.cpp new file mode 100644 index 0000000000000000000000000000000000000000..27071579f940a4ecf0d14029e8f1117dd3566436 --- /dev/null +++ b/paddle/utils/tests/test_ClassRegistrarLib.cpp @@ -0,0 +1,31 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. + +Licensed 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 "test_ClassRegistrarLib.h" +#include +BaseClass::~BaseClass() {} + +class TestRegistrar : public BaseClass { +public: + TestRegistrar() {} + + virtual ~TestRegistrar() {} +}; + +static paddle::InitFunction init([] { + gTestRegistrar_.registerClass( + "test", []() -> BaseClass* { return new TestRegistrar(); }); +}); + +PADDLE_REGISTER_FORCE_LINK_FILE(test_registrar); diff --git a/paddle/utils/tests/test_ClassRegistrarLib.h b/paddle/utils/tests/test_ClassRegistrarLib.h new file mode 100644 index 0000000000000000000000000000000000000000..de2d02e70cc7b02dc7ec8a489b899ce13a641eb2 --- /dev/null +++ b/paddle/utils/tests/test_ClassRegistrarLib.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. + +Licensed 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. */ + +#pragma once +#include "paddle/utils/ClassRegistrar.h" + +class BaseClass { +public: + virtual ~BaseClass(); +}; + +extern paddle::ClassRegistrar gTestRegistrar_;