cmake_minimum_required(VERSION 3.13) project(piper C CXX) set(CMAKE_DEBUG_POSTFIX d) file(READ "${CMAKE_CURRENT_LIST_DIR}/VERSION" piper_version) string(STRIP ${piper_version} piper_version) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) option(PIPER_BUILD_STATIC "Build as static libs" TRUE) option(PIPER_BUILD_LIB_ONLY "Build only libs, no exe" TRUE) if(MSVC) # Force compiler to use UTF-8 for IPA constants add_compile_options("$<$:/utf-8>") add_compile_options("$<$:/utf-8>") elseif(NOT APPLE) # Linux flags string(APPEND CMAKE_CXX_FLAGS " -Wall -Wextra -Wl,-rpath,'$ORIGIN'") string(APPEND CMAKE_C_FLAGS " -Wall -Wextra") endif() if (NOT PIPER_BUILD_LIB_ONLY) add_executable(piper src/cpp/main.cpp src/cpp/piper.cpp) add_executable(test_piper src/cpp/test.cpp src/cpp/piper.cpp) else() if (PIPER_BUILD_STATIC) set(BUILD_PIPER_LIB_TYPE STATIC) else() set(BUILD_PIPER_LIB_TYPE SHARED) endif() add_library(piper ${BUILD_PIPER_LIB_TYPE} src/cpp/piper.cpp) endif() # NOTE: external project prefix are shortened because of path length restrictions on Windows # NOTE: onnxruntime is pulled from piper-phonemize # ---- fmt --- if(NOT DEFINED FMT_DIR) set(FMT_VERSION "10.0.0") set(FMT_DIR ${CMAKE_INSTALL_PREFIX}) include(ExternalProject) ExternalProject_Add( fmt_external PREFIX "${CMAKE_CURRENT_BINARY_DIR}/f" URL "https://github.com/fmtlib/fmt/archive/refs/tags/${FMT_VERSION}.zip" CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} CMAKE_ARGS -DCMAKE_DEBUG_POSTFIX=d CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${FMT_DIR} CMAKE_ARGS -DFMT_TEST:BOOL=OFF # Don't build all the tests ) add_dependencies(piper fmt_external) if (NOT PIPER_BUILD_LIB_ONLY) add_dependencies(test_piper fmt_external) endif() endif() # ---- spdlog --- if(NOT DEFINED SPDLOG_DIR) set(SPDLOG_DIR ${CMAKE_INSTALL_PREFIX}) set(SPDLOG_VERSION "1.12.0") ExternalProject_Add( spdlog_external PREFIX "${CMAKE_CURRENT_BINARY_DIR}/s" URL "https://github.com/gabime/spdlog/archive/refs/tags/v${SPDLOG_VERSION}.zip" CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} CMAKE_ARGS -DCMAKE_DEBUG_POSTFIX=d CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${SPDLOG_DIR} CMAKE_ARGS -DSPDLOG_BUILD_SHARED:BOOL=OFF # Don't build shared ) add_dependencies(piper spdlog_external) if (NOT PIPER_BUILD_LIB_ONLY) add_dependencies(test_piper spdlog_external) endif() endif() # ---- piper-phonemize --- if(NOT DEFINED PIPER_PHONEMIZE_DIR) set(PIPER_PHONEMIZE_DIR ${CMAKE_INSTALL_PREFIX}) ExternalProject_Add( piper_phonemize_external PREFIX "${CMAKE_CURRENT_BINARY_DIR}/p" URL "https://github.com/rhasspy/piper-phonemize/archive/refs/heads/master.zip" CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} CMAKE_ARGS -DCMAKE_DEBUG_POSTFIX=d CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${PIPER_PHONEMIZE_DIR} CMAKE_ARGS -DBUILD_TESTING:BOOL=OFF CMAKE_ARGS -DPHONEMIZE_BUILD_STATIC:BOOL=${PIPER_BUILD_STATIC} PATCH_COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/patch/phonemize-CMakeLists.txt" /CMakeLists.txt ) add_dependencies(piper piper_phonemize_external) if (NOT PIPER_BUILD_LIB_ONLY) add_dependencies(test_piper piper_phonemize_external) endif() endif() # ---- Declare executable ---- if((NOT MSVC) AND (NOT APPLE) AND (NOT PIPER_BUILD_STATIC)) # Linux flags string(APPEND CMAKE_CXX_FLAGS " -Wall -Wextra -Wl,-rpath,'$ORIGIN'") string(APPEND CMAKE_C_FLAGS " -Wall -Wextra") set(PIPER_EXTRA_LIBRARIES "piper -static-libgcc -static-libstdc++ pthread") elseif(WIN32) set(PIPER_EXTRA_LIBRARIES "Dbghelp.lib") endif() set(WPROTO_PREFIX "") if(WIN32) # on windows protobuf is build with a lib suffix set(WPROTO_PREFIX "lib") endif() set(DEPENDS_LIBS espeak-ng piper_phonemize onnxruntime_session onnxruntime_optimizer onnxruntime_providers onnxruntime_util onnxruntime_framework onnxruntime_graph onnxruntime_common onnxruntime_mlas onnxruntime_flatbuffers onnx onnx_proto absl_base absl_throw_delegate absl_raw_hash_set absl_hash absl_city absl_low_level_hash re2 ucd fmt spdlog ${WPROTO_PREFIX}protobuf-lite) if (CMAKE_SYSTEM_NAME STREQUAL "Android") set(DEPENDS_LIBS ${DEPENDS_LIBS} nsync_cpp cpuinfo clog) set(PIPER_EXTRA_LIBRARIES ${PIPER_EXTRA_LIBRARIES} log) endif() if(NOT WIN32) find_package(Threads) set(PIPER_EXTRA_LIBRARIES ${PIPER_EXTRA_LIBRARIES} Threads::Threads) endif() set(DEPENDS_IMPORTED_LIBS "") foreach(DEP IN LISTS DEPENDS_LIBS) if(WIN32) set(DEBUG_DLIB "") set(RELEASE_DLIB "") if (EXISTS "${CMAKE_INSTALL_PREFIX}/lib/Debug/${CMAKE_STATIC_LIBRARY_PREFIX}${DEP}${CMAKE_DEBUG_POSTFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}") set(DEBUG_DLIB ${CMAKE_INSTALL_PREFIX}/lib/Debug/${CMAKE_STATIC_LIBRARY_PREFIX}${DEP}${CMAKE_DEBUG_POSTFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}) elseif (EXISTS "${CMAKE_INSTALL_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${DEP}${CMAKE_DEBUG_POSTFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}") set(DEBUG_DLIB ${CMAKE_INSTALL_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${DEP}${CMAKE_DEBUG_POSTFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}) endif() if (EXISTS "${CMAKE_INSTALL_PREFIX}/lib/Release/${CMAKE_STATIC_LIBRARY_PREFIX}${DEP}${CMAKE_STATIC_LIBRARY_SUFFIX}") set(RELEASE_DLIB ${CMAKE_INSTALL_PREFIX}/lib/Release/${CMAKE_STATIC_LIBRARY_PREFIX}${DEP}${CMAKE_STATIC_LIBRARY_SUFFIX}) elseif (EXISTS "${CMAKE_INSTALL_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${DEP}${CMAKE_STATIC_LIBRARY_SUFFIX}") set(RELEASE_DLIB ${CMAKE_INSTALL_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${DEP}${CMAKE_STATIC_LIBRARY_SUFFIX}) endif() if (NOT DEBUG_DLIB STREQUAL "" AND NOT RELEASE_DLIB STREQUAL "") set(DEPENDS_IMPORTED_LIBS ${DEPENDS_IMPORTED_LIBS} debug ${DEBUG_DLIB} optimized ${RELEASE_DLIB}) elseif (NOT RELEASE_DLIB STREQUAL "") set(DEPENDS_IMPORTED_LIBS ${DEPENDS_IMPORTED_LIBS} ${RELEASE_DLIB}) else() message("Dependencie lib not found : ${DEP}") endif() else() set(DEPENDS_IMPORTED_LIBS ${DEPENDS_IMPORTED_LIBS} ${CMAKE_INSTALL_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${DEP}${CMAKE_STATIC_LIBRARY_SUFFIX}) endif() endforeach() target_link_libraries(piper PUBLIC ${DEPENDS_IMPORTED_LIBS} ${PIPER_EXTRA_LIBRARIES} ) target_link_directories(piper PUBLIC ${FMT_DIR}/lib ${SPDLOG_DIR}/lib ${PIPER_PHONEMIZE_DIR}/lib ) target_include_directories(piper PUBLIC ${FMT_DIR}/include ${SPDLOG_DIR}/include ${PIPER_PHONEMIZE_DIR}/include ${CMAKE_INSTALL_PREFIX}/include/onnxruntime/core/session ) target_compile_definitions(piper PUBLIC LIBESPEAK_NG_STATIC _PIPER_VERSION=${piper_version}) target_include_directories(${PROJECT_NAME} PUBLIC $ $ ) include(CMakePackageConfigHelpers) # Generate cmake configuration scripts set(piper_GENERATED_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated) set(piper_VERSION_CONFIG ${piper_GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake) set(piper_PROJECT_CONFIG ${piper_GENERATED_DIR}/${PROJECT_NAME}Config.cmake) set(piper_TARGETS_EXPORT_NAME ${PROJECT_NAME}Targets) set(piper_CONFIG_INSTALL_DIR lib/cmake/${PROJECT_NAME}) set(piper_NAMESPACE "${PROJECT_NAME}::") # Create a version config file write_basic_package_version_file(${piper_VERSION_CONFIG} VERSION ${piper_version} COMPATIBILITY SameMajorVersion) # Create a project config file configure_file(${PROJECT_SOURCE_DIR}/Config.cmake.in ${piper_PROJECT_CONFIG} @ONLY) # Install to the specified directory install(FILES ${piper_VERSION_CONFIG} ${piper_PROJECT_CONFIG} DESTINATION ${piper_CONFIG_INSTALL_DIR}) install(EXPORT ${piper_TARGETS_EXPORT_NAME} NAMESPACE ${piper_NAMESPACE} DESTINATION ${piper_CONFIG_INSTALL_DIR}) # Set standard installation directories set(RUNTIME_DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) set(LIBRARY_DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) set(ARCHIVE_DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) set(INCLUDES_DESTINATION ${CMAKE_INSTALL_PREFIX}/include) install(TARGETS ${PROJECT_NAME} EXPORT ${piper_TARGETS_EXPORT_NAME} RUNTIME DESTINATION ${RUNTIME_DESTINATION} LIBRARY DESTINATION ${LIBRARY_DESTINATION} ARCHIVE DESTINATION ${ARCHIVE_DESTINATION}) # ---- Declare test ---- if (NOT PIPER_BUILD_LIB_ONLY) include(CTest) enable_testing() add_test( NAME test_piper COMMAND test_piper "${CMAKE_SOURCE_DIR}/etc/test_voice.onnx" "${PIPER_PHONEMIZE_DIR}/share/espeak-ng-data" "${CMAKE_CURRENT_BINARY_DIR}/test.wav" ) target_compile_features(test_piper PUBLIC cxx_std_17) target_include_directories( test_piper PUBLIC ${FMT_DIR}/include ${SPDLOG_DIR}/include ${PIPER_PHONEMIZE_DIR}/include ) target_link_directories( test_piper PUBLIC ${FMT_DIR}/lib ${SPDLOG_DIR}/lib ${PIPER_PHONEMIZE_DIR}/lib ) target_link_libraries(test_piper PUBLIC fmt spdlog espeak-ng piper_phonemize onnxruntime ) endif() # ---- Declare install targets ---- set_target_properties(piper PROPERTIES PUBLIC_HEADER "src/cpp/piper.hpp;src/cpp/json.hpp") include(GNUInstallDirs) if (PIPER_BUILD_LIB_ONLY) install( TARGETS piper DESTINATION ${CMAKE_INSTALL_LIBDIR}) else() install( TARGETS piper DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() if(WIN32) install( DIRECTORY ${PIPER_PHONEMIZE_DIR}/share/espeak-ng-data DESTINATION ${CMAKE_INSTALL_PREFIX}/share ) endif() install( FILES ${PIPER_PHONEMIZE_DIR}/share/libtashkeel_model.ort DESTINATION ${CMAKE_INSTALL_PREFIX}/share ) INSTALL(TARGETS piper LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/piper )