Skip to content

Commit

Permalink
Expose CTranslate2::ctranslate2 as CMake package (OpenNMT#1178)
Browse files Browse the repository at this point in the history
* Expose CTranslate2::ctranslate2 as CMake package

* Add docs for C++ Library use

* EOF new-line

* Move COPY python upwards
  • Loading branch information
HennerM authored Apr 22, 2023
1 parent ba3b77c commit ed9ec39
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 9 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
*.pyc
/.vs
/build

CMake*.json
.idea
python/build/
python/ctranslate2.egg-info/
python/dist/
.cache
docs/build/
docs/python/
72 changes: 64 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,20 @@ if(APPLE)
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.13)
endif()


# Read version from version.py
file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/python/ctranslate2/version.py VERSION_FILE)
foreach(line IN LISTS VERSION_FILE)
if (line MATCHES "__version__")
string(REGEX MATCH "[0-9.]+" CTRANSLATE2_VERSION ${line})
break()
endif()
endforeach()

if(NOT CTRANSLATE2_VERSION)
message(FATAL_ERROR "Version can't be read from version.py")
endif()

if(MSVC)
if(BUILD_SHARED_LIBS)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
Expand All @@ -72,9 +86,6 @@ endif()
find_package(Threads)
add_subdirectory(third_party/spdlog EXCLUDE_FROM_ALL)

set(PUBLIC_INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR}/include
)
set(PRIVATE_INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}/third_party
Expand Down Expand Up @@ -499,12 +510,22 @@ else()
add_library(${PROJECT_NAME} ${SOURCES})
endif()

include(GenerateExportHeader)
generate_export_header(${PROJECT_NAME})
set_property(TARGET ${PROJECT_NAME} PROPERTY VERSION ${CTRANSLATE2_VERSION})
set_property(TARGET ${PROJECT_NAME} PROPERTY SOVERSION 3)
set_property(TARGET ${PROJECT_NAME} PROPERTY
INTERFACE_${PROJECT_NAME}_MAJOR_VERSION 3)
set_property(TARGET ${PROJECT_NAME} APPEND PROPERTY
COMPATIBLE_INTERFACE_STRING ${PROJECT_NAME}_MAJOR_VERSION
)

list(APPEND LIBRARIES ${CMAKE_DL_LIBS})
target_link_libraries(${PROJECT_NAME} PRIVATE ${LIBRARIES})
target_include_directories(${PROJECT_NAME} BEFORE
PUBLIC ${PUBLIC_INCLUDE_DIRECTORIES}
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include>
PRIVATE ${PRIVATE_INCLUDE_DIRECTORIES}
)
)

if(BUILD_TESTS)
add_subdirectory(tests)
Expand All @@ -517,13 +538,48 @@ if (BUILD_CLI)
endif()

install(
TARGETS ${PROJECT_NAME}
TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}Targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
)
install(
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/"
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
FILES_MATCHING PATTERN "*.h*"
)
)

include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}/${PROJECT_NAME}ConfigVersion.cmake"
VERSION ${CTRANSLATE2_VERSION}
COMPATIBILITY AnyNewerVersion
)

export(EXPORT ${PROJECT_NAME}Targets
FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}/${PROJECT_NAME}Targets.cmake"
NAMESPACE CTranslate2::
)
configure_file(cmake/${PROJECT_NAME}Config.cmake
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}/${PROJECT_NAME}Config.cmake"
COPYONLY
)

set(ConfigPackageLocation lib/cmake/${PROJECT_NAME})
install(EXPORT ${PROJECT_NAME}Targets
FILE
${PROJECT_NAME}Targets.cmake
NAMESPACE
CTranslate2::
DESTINATION
${ConfigPackageLocation}
)
install(
FILES
cmake/${PROJECT_NAME}Config.cmake
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}/${PROJECT_NAME}ConfigVersion.cmake"
DESTINATION
${ConfigPackageLocation}
COMPONENT
Devel
)
1 change: 1 addition & 0 deletions cmake/ctranslate2Config.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include("${CMAKE_CURRENT_LIST_DIR}/ctranslate2Targets.cmake")
3 changes: 2 additions & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ COPY third_party third_party
COPY cli cli
COPY include include
COPY src src
COPY cmake cmake
COPY python python
COPY CMakeLists.txt .

ARG CXX_FLAGS
Expand All @@ -60,7 +62,6 @@ RUN mkdir build && \

ENV LANG=en_US.UTF-8
COPY README.md .
COPY python python

RUN cd python && \
python3 -m pip --no-cache-dir install -r install_requirements.txt && \
Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ The documentation includes installation instructions, usage guides, and API refe
:maxdepth: 1

quickstart.md
quickstart_cpp.md
installation.md

.. toctree::
Expand Down
84 changes: 84 additions & 0 deletions docs/quickstart_cpp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# C++ Quickstart

Start using the CTranslate2 library in your own C++ project.

**1\. Compile and Install CTranslate2**

```bash
mkdir build && cd build
cmake ..
make -j4 install
```

It's important that the library is getting installed into a directory that is on the CMAKE_PREFIX_PATH, otherwise you can install to a custom directory, e.g.:
```bash
export CTRANSLATE_INSTALL_PATH=$(pwd)/install
cmake .. -DCMAKE_INSTALL_PREFIX=$CTRANSLATE_INSTALL_PATH
make -j4 install
```


See [installation guide][installation.md] for more info.

**2\. Add CTranslate2 to your CMakeLists.txt**

```cmake
cmake_minimum_required (VERSION 2.8.11)
project (CTRANSLATE2_DEMO)
find_package(ctranslate2)
add_executable (main main.cpp)
target_link_libraries(main CTranslate2::ctranslate2)
```


**3\. Have a model ready in the CTranslate2 format**

```bash
ct2-transformers-converter --model Helsinki-NLP/opus-mt-en-de --output_dir opus-mt-en-de
```

**4\. Write the translation C++ code using the API**

You will need to have your input string tokenised,
which depends on what type of model you are using.
Have a look at the guides to get tokens from your input string.

```cpp
#include <iostream>
#include <vector>

#include "ctranslate2/translator.h"

int main(int argc, char* argv[]) {

std::string model_path("opus-mt-en-de");
const auto model = ctranslate2::models::Model::load(model_path);
const ctranslate2::models::ModelLoader model_loader(model_path);
ctranslate2::Translator translator(model_loader);

std::vector<std::vector<std::string>> batch = {{"▁Hello", "▁World", "!", "</s>"}};
auto translation = translator.translate_batch(batch);
for (auto &token: translation[0].output()) {
std::cout << token << ' ';
}
std::cout << std::endl;
}
```
**5\. Compile and run the example**
```bash
cmake .
make
./main
```
If you have installed the CTranslate lib to a custom path use: `cmake -DCMAKE_PREFIX_PATH=$CTRANSLATE_INSTALL_PATH .`


This code should print the output tokens:

> ▁Hall o ▁Welt </s>
If that's the case, you successfully converted and executed a translation model with CTranslate2!
(De)tokenisation is handled outside of CTranslate2,
so make sure to properly tokenise the input and detokenise the output.

0 comments on commit ed9ec39

Please sign in to comment.