Browse Source

build: support building with cmake (#1570)

Fixes: #1547

- Implement building and testing with cmake
- Download libsonic from repository (when enabled and not available as
system library), ref: #650
- Migrate android native build to cmake
- Migrate CI to cmake
- Add windows CI

TODO (might be done in separate PR):
- Building as [cmake external
project](https://cmake.org/cmake/help/latest/module/ExternalProject.html)
- Building for package managers (deb, rpm, ...)
- Strip out `vcproj` - _to be discussed_
- Strip out `autotools` after next release
- Update build documentation for `cmake`
master
Alexander Epaneshnikov 2 years ago
parent
commit
d25030c668
No account linked to committer's email address

+ 3
- 5
.github/workflows/android.yml View File

@@ -16,18 +16,16 @@ jobs:
config: [debug, release]
include:
- config: debug
target: assembleDebug
apkname: espeak-debug.apk
- config: release
target: assembleRelease
apkname: espeak-release-unsigned.apk
name: Build ${{ matrix.config }} APK
steps:
- uses: actions/checkout@v3
- name: autoconf
run: ./autogen.sh ; chmod -x INSTALL m4/*.m4
- name: configure
run: ./configure --with-gradle=$(pwd)/android/gradlew
- name: make
run: make apk-${{ matrix.config }}
run: cd android ; ./gradlew ${{ matrix.target }}
- name: upload
uses: actions/upload-artifact@v3
with:

+ 12
- 16
.github/workflows/ci.yml View File

@@ -70,7 +70,7 @@ jobs:
- sanitizer: "memory"
configenv: "CC=clang CXX=clang++"
sanitizer_cflags: "-fsanitize=memory -fsanitize-memory-track-origins=2"
config: "--without-pcaudiolib --without-sonic"
config: "-DUSE_LIBPCAUDIO:BOOL=OFF -DUSE_LIBSONIC:BOOL=OFF"
sanitize_env: "MSAN_OPTIONS=exitcode=42"

- sanitizer: "thread"
@@ -81,7 +81,7 @@ jobs:
sanitize_env: "UBSAN_OPTIONS=halt_on_error=1"

- sanitizer: "valgrind"
sanitize_env: 'VALGRIND="libtool --mode=execute valgrind --track-origins=yes --leak-check=full --error-exitcode=1"'
sanitize_env: 'VALGRIND="valgrind --track-origins=yes --leak-check=full --error-exitcode=1"'
exclude:
- os: macos
@@ -183,7 +183,7 @@ jobs:
sudo apt-get install ronn kramdown python3
- name: apt-arch-deps
if: matrix.os == 'ubuntu' && matrix.cross == 'no'
run: "sudo apt-get install libtool-bin valgrind g++-12-multilib linux-libc-dev:${{ matrix.arch }} libpcaudio-dev:${{ matrix.arch }} libsonic-dev:${{ matrix.arch }} libstdc++-12-dev:${{ matrix.arch }} libc6-dbg:${{ matrix.arch }}"
run: "sudo apt-get install cmake valgrind g++-12-multilib linux-libc-dev:${{ matrix.arch }} libpcaudio-dev:${{ matrix.arch }} libsonic-dev:${{ matrix.arch }} libstdc++-12-dev:${{ matrix.arch }} libc6-dbg:${{ matrix.arch }}"
- name: apt-cross-deps
if: matrix.cross == 'yes'
run: sudo apt-get install qemu-user g++-12-${{ matrix.arch }}-${{ matrix.sys }}
@@ -194,8 +194,7 @@ jobs:
# MacOS - dependencies
- name: brew-deps
if: matrix.os == 'macos'
run: brew install libtool automake ronn OJFord/homebrew-formulae/kramdown &&
brew install --HEAD anarchivist/espeak-ng/waywardgeek-sonic
run: brew install cmake ronn OJFord/homebrew-formulae/kramdown
- name: brew-compile-deps
if: matrix.os == 'macos' && matrix.compiler == 'gcc'
run: brew install gcc@12
@@ -204,11 +203,6 @@ jobs:
- uses: actions/checkout@v3

# Configure
- name: autoconf
run: |
./autogen.sh
chmod -x INSTALL m4/*.m4

- name: configure
run: |
[ 'x${{ matrix.compiler }}' = 'xgcc' ] && export CC="${{ matrix.ccarch }}-${{ matrix.sys }}-gcc-12"
@@ -218,19 +212,21 @@ jobs:
[ 'x${{ matrix.cross }}' = 'xyes' ] && export LD="${{ matrix.ccarch }}-${{ matrix.sys }}-ld"
export CFLAGS="-g -Og -fno-omit-frame-pointer ${{ matrix.compiler_flags }} ${{ matrix.sanitizer_cflags }} ${{ matrix.archcflags }}"
export CXXFLAGS="-g -Og -fno-omit-frame-pointer ${{ matrix.compiler_flags }} ${{ matrix.sanitizer_cflags }} ${{ matrix.archcflags }}"
./configure --host=${{ matrix.arch }}-${{ matrix.sys }} ${{ matrix.config }}
cmake -Bbuild ${{ matrix.config }} -DCMAKE_SYSTEM_PROCESSOR=${{ matrix.arch }} -DUSE_ASYNC:BOOL=OFF

- name: config-failed-upload
if: ${{ failure() }}
uses: actions/upload-artifact@v3
with:
name: config-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.compiler }}-${{ matrix.sanitizer }}.log
path: config.log
name: cmake-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.compiler }}-${{ matrix.sanitizer }}-builddir
path: build

# Build and test
- name: make-binary
run: make src/speak-ng src/espeak-ng
run: cmake --build build --target espeak-ng
- name: make-data
run: ${{ matrix.sanitize_env }} ${{ matrix.runenv }} make all-am
run: ${{ matrix.sanitize_env }} ${{ matrix.runenv }} cmake --build build --target data
- name: test
run: ${{ matrix.sanitize_env }} ${{ matrix.runenv }} make check
run: |
${{ matrix.sanitize_env }} ${{ matrix.runenv }} cmake --build build --target tests
${{ matrix.sanitize_env }} ${{ matrix.runenv }} ctest --test-dir build -Ttest -j1 --output-on-failure

+ 13
- 15
.github/workflows/dist.yml View File

@@ -8,7 +8,7 @@ on:
branches: [ master ]

env:
deps: libpcaudio-dev libsonic-dev ronn kramdown python3
deps: cmake libpcaudio-dev libsonic-dev ronn kramdown python3

jobs:

@@ -37,10 +37,8 @@ jobs:
if: matrix.arch == 'x86-32'
- name: dependencies
run: sudo apt-get update && sudo apt-get install ${{ env.deps }} reprotest ${{ matrix.archdeps }}
- name: autoconf
run: ./autogen.sh ; chmod -x INSTALL m4/*.m4
- name: run
run: reprotest 'CFLAGS="${{ matrix.archconfigflags }}" CXXFLAGS="${{ matrix.archconfigflags }}" ./configure --without-gradle && make clean && make && make check && touch success' success
run: reprotest 'CFLAGS="${{ matrix.archconfigflags }}" CXXFLAGS="${{ matrix.archconfigflags }}" rm -rf build && cmake -Bbuild -DUSE_ASYNC:BOOL=OFF && cmake --build build && ctest --test-dir build -Ttest -j1 --output-on-failure && touch success' success

distcheck:

@@ -50,21 +48,21 @@ jobs:
- uses: actions/checkout@v3
- name: dependencies
run: sudo apt-get update && sudo apt-get install ${{ env.deps }}
- name: autoconf
run: ./autogen.sh ; chmod -x INSTALL m4/*.m4
- name: configure
run: ./configure
run: cmake -Bbuild -DUSE_ASYNC:BOOL=OFF
- name: make
run: make
run: cmake --build build
- name: make check
run: make check
- name: make dist
run: make dist
run: ctest --test-dir build -Ttest -j1 --output-on-failure

- name: make package_source
run: cmake --build build --target package_source
- name: unpack
run: mkdir unpack && tar -C unpack -xf *.tar.gz
run: mkdir unpack && tar -C unpack -xf build/espeak-ng-*-Source.tar.bz2

- name: re-configure
run: cd unpack/espeak-ng-* && ./configure
run: cd unpack/espeak-ng-* && cmake -Bbuild -DUSE_ASYNC:BOOL=OFF
- name: re-make
run: cd unpack/espeak-ng-* && make
run: cd unpack/espeak-ng-* && cmake --build build
- name: re-make check
run: cd unpack/espeak-ng-* && make check
run: cd unpack/espeak-ng-* && ctest --test-dir build -Ttest -j1 --output-on-failure

+ 21
- 0
.github/workflows/windows.yml View File

@@ -0,0 +1,21 @@
name: Windows

on:
workflow_dispatch:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
build:
runs-on: windows-latest
name: build
steps:
- uses: actions/checkout@v3
- name: configure
run: cmake -Bbuild -DUSE_ASYNC:BOOL=OFF
- name: make
run: cmake --build build
- name: make check
run: ctest --test-dir build -Ttest -C Debug -j1 --output-on-failure

+ 31
- 0
CMakeLists.txt View File

@@ -0,0 +1,31 @@
cmake_minimum_required(VERSION 3.8)

project(espeak-ng
VERSION 1.52.0.1
DESCRIPTION "open source speech synthesizer that supports more than hundred languages and accents"
HOMEPAGE_URL "https://github.com/espeak-ng/espeak-ng"
)

include(CTest)

include(cmake/deps.cmake)
include(cmake/config.cmake)
add_subdirectory(src)
include(cmake/data.cmake)

include(cmake/package.cmake)
include(CPack)

include(CTest)
add_subdirectory(tests)

option(BUILD_SHARED_LIBS "Build shared libraries" OFF)

message(STATUS "Configuration:")
message(STATUS " shared: ${BUILD_SHARED_LIBS}")
message(STATUS " mbrola: ${USE_MBROLA} (${MBROLA_BIN})")
message(STATUS " libsonic: ${USE_LIBSONIC} (${SONIC_LIB} ${SONIC_INC})")
message(STATUS " libpcaudio: ${USE_LIBPCAUDIO} (${PCAUDIO_LIB} ${PCAUDIO_INC})")
message(STATUS " klatt: ${USE_KLATT}")
message(STATUS " speech-player: ${USE_SPEECHPLAYER}")
message(STATUS " async: ${USE_ASYNC}")

+ 49
- 37
android/build.gradle View File

@@ -25,6 +25,49 @@ dependencies {
androidTestImplementation 'org.hamcrest:hamcrest-all:1.3'
}

android {
compileSdk 33
ndkVersion "25.1.8937393"
namespace "com.reecedunn.espeak"

defaultConfig {
minSdk 19
targetSdk 33
versionCode 22
versionName "1.52-dev"

externalNativeBuild {
cmake {
arguments "-DUSE_ASYNC:BOOL=OFF", "-DUSE_MBROLA:BOOL=OFF"
targets "ttsespeak", "espeak-data"
}
}
}

externalNativeBuild {
cmake {
path "jni/CMakeLists.txt"
version "3.22.1"
}
}

sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
res.srcDirs = ['res']
}
androidTest.setRoot('eSpeakTests')
androidTest {
java.srcDirs = ['eSpeakTests/src']
}
}

lint {
abortOnError false
}
}

tasks.register('checkData') {
doFirst {
assert file("../espeak-ng-data/en_dict").exists()
@@ -37,13 +80,12 @@ tasks.register('checkData') {
}

tasks.register('createDataArchive', Zip) {
dependsOn tasks.checkData
preserveFileTimestamps = false
reproducibleFileOrder = true
archiveFileName = "espeakdata.zip"
destinationDirectory = file("res/raw")

from("../espeak-ng-data/") {
from("build/generated/espeak-ng-data/") {
into "espeak-ng-data"
}
}
@@ -61,40 +103,10 @@ tasks.register('createDataVersion', Copy) {
rename { return 'espeakdata_version' }
into file("./res/raw")
}
preBuild.dependsOn createDataVersion


android {
compileSdk 33
ndkVersion "25.1.8937393"
namespace "com.reecedunn.espeak"

defaultConfig {
minSdk 19
targetSdk 30
versionCode 22
versionName "1.52-dev"
}

externalNativeBuild {
ndkBuild {
path "jni/Android.mk"
}
}

sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
res.srcDirs = ['res']
}
androidTest.setRoot('eSpeakTests')
androidTest {
java.srcDirs = ['eSpeakTests/src']
}
}

lint {
abortOnError false
}
project.afterEvaluate {
tasks.checkData.dependsOn(externalNativeBuildDebug)
tasks.createDataArchive.dependsOn(externalNativeBuildDebug)
javaPreCompileDebug.dependsOn(tasks.createDataVersion)
javaPreCompileRelease.dependsOn(tasks.createDataVersion)
}

+ 0
- 83
android/jni/Android.mk View File

@@ -1,83 +0,0 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

#LOCAL_CFLAGS = -std=c11 # speechplayer is c++ code

# ucd-tools wide-character compatibility support:

UCDTOOLS_SRC_PATH := ../../src/ucd-tools/src
UCDTOOLS_SRC_FILES := \
$(subst $(LOCAL_PATH)/$(UCDTOOLS_SRC_PATH),$(UCDTOOLS_SRC_PATH),$(wildcard $(LOCAL_PATH)/$(UCDTOOLS_SRC_PATH)/*.c*))

LOCAL_SRC_FILES += $(UCDTOOLS_SRC_FILES)

SPEECHPLAYER_SRC_FILES := \
../../src/speechPlayer/src/frame.cpp \
../../src/speechPlayer/src/speechPlayer.cpp \
../../src/speechPlayer/src/speechWaveGenerator.cpp

LOCAL_SRC_FILES += $(SPEECHPLAYER_SRC_FILES)

ESPEAK_SOURCES := \
src/libespeak-ng/common.c \
src/libespeak-ng/compiledata.c \
src/libespeak-ng/compiledict.c \
src/libespeak-ng/compilembrola.c \
src/libespeak-ng/dictionary.c \
src/libespeak-ng/encoding.c \
src/libespeak-ng/error.c \
src/libespeak-ng/espeak_api.c \
src/libespeak-ng/ieee80.c \
src/libespeak-ng/intonation.c \
src/libespeak-ng/klatt.c \
src/libespeak-ng/langopts.c \
src/libespeak-ng/mnemonics.c \
src/libespeak-ng/numbers.c \
src/libespeak-ng/phoneme.c \
src/libespeak-ng/phonemelist.c \
src/libespeak-ng/readclause.c \
src/libespeak-ng/setlengths.c \
src/libespeak-ng/soundicon.c \
src/libespeak-ng/spect.c \
src/libespeak-ng/speech.c \
src/libespeak-ng/sPlayer.c \
src/libespeak-ng/ssml.c \
src/libespeak-ng/synthdata.c \
src/libespeak-ng/synthesize.c \
src/libespeak-ng/synth_mbrola.c \
src/libespeak-ng/translate.c \
src/libespeak-ng/translateword.c \
src/libespeak-ng/tr_languages.c \
src/libespeak-ng/voices.c \
src/libespeak-ng/wavegen.c

ESPEAK_SRC_PATH := ../../src
ESPEAK_SRC_FILES := \
$(subst src/,$(ESPEAK_SRC_PATH)/,$(ESPEAK_SOURCES))

LOCAL_CFLAGS += -DINCLUDE_KLATT -DINCLUDE_SPEECHPLAYER -DINCLUDE_SONIC -DHAVE_ENDIAN_H
LOCAL_SRC_FILES += \
$(filter-out $(BLACKLIST_SRC_FILES),$(ESPEAK_SRC_FILES))

# JNI

LOCAL_SRC_FILES += \
$(subst $(LOCAL_PATH)/jni,jni,$(wildcard $(LOCAL_PATH)/jni/*.c))

# Common

LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/include \
$(LOCAL_PATH)/$(UCDTOOLS_SRC_PATH)/include \
$(LOCAL_PATH)/../../src/speechPlayer/include \
$(LOCAL_PATH)/$(ESPEAK_SRC_PATH)/include \
$(LOCAL_PATH)/$(ESPEAK_SRC_PATH)/include/compat

LOCAL_LDLIBS := \
-llog

LOCAL_MODULE := libttsespeak
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false

include $(BUILD_SHARED_LIBRARY)

+ 26
- 0
android/jni/CMakeLists.txt View File

@@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 3.8)

project(espeak-android)

add_subdirectory(../../ espeakng)

add_custom_target(
espeak-data
COMMAND ${CMAKE_COMMAND} -B${CMAKE_CURRENT_BINARY_DIR}/../espeak-data ${CMAKE_CURRENT_SOURCE_DIR}/../../
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/../espeak-data --target data
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/../espeak-data/espeak-ng-data ${CMAKE_SOURCE_DIR}/../build/generated/espeak-ng-data
)

message(STATUS "Data: ${CMAKE_CURRENT_SOURCE_DIR}")

find_library(A_LOG log)

add_library(ttsespeak SHARED
jni/eSpeakService.c
)
target_include_directories(ttsespeak PRIVATE
include
)
target_link_libraries(ttsespeak PRIVATE
espeak-ng ${A_LOG}
)

+ 1
- 0
android/jni/jni/eSpeakService.c View File

@@ -26,6 +26,7 @@
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <jni.h>

#include <espeak/speak_lib.h>

+ 14
- 0
cmake/config.cmake View File

@@ -0,0 +1,14 @@
include(CheckSymbolExists)
check_symbol_exists(mkstemp "stdlib.h" HAVE_MKSTEMP)

option(USE_MBROLA "Use mbrola for speech synthesis" ${HAVE_MBROLA})
option(USE_LIBSONIC "Use libsonit for faster speech rates" ${HAVE_LIBSONIC})
option(USE_LIBPCAUDIO "Use libPcAudio for sound output" ${HAVE_LIBPCAUDIO})

option(USE_KLATT "Use klatt for speech synthesis" ON)
option(USE_SPEECHPLAYER "Use speech-player for speech synthesis" ON)
if (HAVE_PTHREAD)
option(USE_ASYNC "Support asynchronous speech synthesis" ON)
else()
set(USE_ASYNC OFF)
endif()

+ 168
- 0
cmake/data.cmake View File

@@ -0,0 +1,168 @@
list(APPEND _dict_compile_list
af am an ar as az
ba be bg bn bpy bs
ca chr cmn cs cv cy
da de
el en eo es et eu
fa fi fr
ga gd gn grc gu
hak haw he hi hr ht hu hy
ia id io is it
ja jbo
ka kk kl kn kok ko ku ky
la lb lfn lt lv
mi mk ml mr ms mto mt my
nci ne nl nog no
om or
pap pa piqd pl pt py
qdb quc qu qya
ro ru
sd shn si sjn sk sl smj sq sr sv sw
ta te th tk tn tr tt
ug uk ur uz
vi
yue
)

list(APPEND _mbrola_lang_list
af1 ar1 ar2
ca cmn cr1 cs
de2 de4 de6 de8
ee1 en1 es es3 es4
fr
gr1 gr2 grc-de6
he hn1 hu1
ic1 id1 in ir1 it1 it3
jp
la1 lt
ma1 mx1 mx2
nl nz1
pl1 pt1 ptbr ptbr4
ro1
sv sv2
tl1 tr1
us us3
vz
)

set(DATA_DIST_ROOT ${CMAKE_CURRENT_BINARY_DIR})
set(DATA_DIST_DIR ${DATA_DIST_ROOT}/espeak-ng-data)
set(PHONEME_TMP_DIR ${DATA_DIST_ROOT}/phsource)
set(DICT_TMP_DIR ${DATA_DIST_ROOT}/dictsource)

set(DATA_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/espeak-ng-data)
set(PHONEME_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/phsource)
set(DICT_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/dictsource)

file(MAKE_DIRECTORY "${DATA_DIST_DIR}")
file(MAKE_DIRECTORY "${DICT_TMP_DIR}")
file(COPY "${DATA_SRC_DIR}/lang" DESTINATION "${DATA_DIST_DIR}")
file(COPY "${DATA_SRC_DIR}/voices/!v" DESTINATION "${DATA_DIST_DIR}/voices")
file(COPY "${PHONEME_SRC_DIR}" DESTINATION "${DATA_DIST_ROOT}")

set(ESPEAK_RUN_ENV ${CMAKE_COMMAND} -E env "ESPEAK_DATA_PATH=${DATA_DIST_ROOT}")
set(ESPEAK_RUN_CMD ${ESPEAK_RUN_ENV} $ENV{VALGRIND} "$<TARGET_FILE:espeak-ng-bin>")

add_custom_command(
OUTPUT "${DATA_DIST_DIR}/intonations"
COMMAND ${ESPEAK_RUN_CMD} --compile-intonations
WORKING_DIRECTORY "${PHONEME_SRC_DIR}"
COMMENT "Compile intonations"
DEPENDS
"$<TARGET_FILE:espeak-ng-bin>"
"${PHONEME_SRC_DIR}/intonation"
)

set(_phon_deps "")

function(check_phon_deps _file)
set(_file "${PHONEME_SRC_DIR}/${_file}")
list(APPEND _phon_deps "${_file}")

file(STRINGS "${_file}" _phon_incs REGEX "include .+")
list(TRANSFORM _phon_incs REPLACE "^[ \t]*include[ \t]+" "")
foreach(_inc ${_phon_incs})
check_phon_deps(${_inc})
endforeach(_inc)
set(_phon_deps ${_phon_deps} PARENT_SCOPE)
endfunction(check_phon_deps)

check_phon_deps("phonemes")

add_custom_command(
OUTPUT
"${DATA_DIST_DIR}/phondata"
"${DATA_DIST_DIR}/phondata-manifest"
"${DATA_DIST_DIR}/phonindex"
"${DATA_DIST_DIR}/phontab"
COMMAND ${ESPEAK_RUN_CMD} --compile-phonemes
WORKING_DIRECTORY "${PHONEME_SRC_DIR}"
COMMENT "Compile phonemes"
DEPENDS
"$<TARGET_FILE:espeak-ng-bin>"
${_phon_deps}
)

list(APPEND _dict_targets)
list(APPEND _mbr_targets)

foreach(_dict_name ${_dict_compile_list})
set(_dict_target "${DATA_DIST_DIR}/${_dict_name}_dict")
set(_dict_deps "")
list(APPEND _dict_targets ${_dict_target})
list(APPEND _dict_deps
"${DICT_SRC_DIR}/${_dict_name}_rules"
"${DICT_SRC_DIR}/${_dict_name}_list"
)

if(EXISTS "${DICT_SRC_DIR}/extra/${_dict_name}_listx")
option(EXTRA_${_dict_name} "Compile extra ${_dict_name} dictionary" ON)
if(EXTRA_${_dict_name})
list(APPEND _dict_deps "${DICT_SRC_DIR}/extra/${_dict_name}_listx")
else()
file(REMOVE "${DICT_TMP_DIR}/${_dict_name}_listx")
endif()
elseif(EXISTS "${DICT_SRC_DIR}/${_dict_name}_listx")
list(APPEND _dict_deps "${DICT_SRC_DIR}/${_dict_name}_listx")
endif()
if(EXISTS "${DICT_SRC_DIR}/${_dict_name}_emoji")
list(APPEND _dict_deps "${DICT_SRC_DIR}/${_dict_name}_emoji")
endif()

add_custom_command(
OUTPUT "${_dict_target}"
COMMAND ${CMAKE_COMMAND} -E copy ${_dict_deps} "${DICT_TMP_DIR}/"
COMMAND ${ESPEAK_RUN_CMD} --compile=${_dict_name}
WORKING_DIRECTORY "${DICT_TMP_DIR}"
DEPENDS
"$<TARGET_FILE:espeak-ng-bin>"
"${DATA_DIST_DIR}/phondata"
"${DATA_DIST_DIR}/intonations"
${_dict_deps}
)
endforeach()

if (HAVE_MBROLA AND USE_MBROLA)
file(COPY "${DATA_SRC_DIR}/voices/mb" DESTINATION "${DATA_DIST_DIR}/voices")
file(MAKE_DIRECTORY "${DATA_DIST_DIR}/mbrola_ph")
foreach(_mbl ${_mbrola_lang_list})
set(_mbl_src "${PHONEME_SRC_DIR}/mbrola/${_mbl}")
set(_mbl_out "${DATA_DIST_DIR}/mbrola_ph/${_mbl}_phtrans")
list(APPEND _mbr_targets ${_mbl_out})
add_custom_command(
OUTPUT "${_mbl_out}"
COMMAND ${ESPEAK_RUN_CMD} --compile-mbrola="${_mbl_src}"
DEPENDS "$<TARGET_FILE:espeak-ng-bin>" "${_mbl_src}"
)
endforeach(_mbl)
endif()

add_custom_target(
data ALL
DEPENDS
"${DATA_DIST_DIR}/intonations"
"${DATA_DIST_DIR}/phondata"
${_dict_targets}
${_mbr_targets}
)
install(DIRECTORY ${DATA_DIST_DIR} DESTINATION share)

+ 33
- 0
cmake/deps.cmake View File

@@ -0,0 +1,33 @@
find_library(SONIC_LIB sonic)
find_path(SONIC_INC "sonic.h")
find_library(PCAUDIO_LIB pcaudio)
find_path(PCAUDIO_INC "pcaudiolib/audio.h")
find_library(PTHREAD_LIB pthread)
find_program(MBROLA_BIN mbrola)

include(FetchContent)

if (PTHREAD_LIB)
set(HAVE_PTHREAD ON)
endif(PTHREAD_LIB)
if (MBROLA_BIN)
set(HAVE_MBROLA ON)
endif(MBROLA_BIN)
if (SONIC_LIB AND SONIC_INC)
set(HAVE_LIBSONIC ON)
else()
FetchContent_Declare(sonic-git
GIT_REPOSITORY https://github.com/waywardgeek/sonic.git
GIT_TAG fbf75c3d6d846bad3bb3d456cbc5d07d9fd8c104
)
FetchContent_MakeAvailable(sonic-git)
FetchContent_GetProperties(sonic-git)
add_library(sonic OBJECT ${sonic-git_SOURCE_DIR}/sonic.c)
target_include_directories(sonic PUBLIC ${sonic-git_SOURCE_DIR})
set(HAVE_LIBSONIC ON)
set(SONIC_LIB sonic)
set(SONIC_INC ${sonic-git_SOURCE_DIR})
endif()
if (PCAUDIO_LIB AND PCAUDIO_INC)
set(HAVE_LIBPCAUDIO ON)
endif()

+ 17
- 0
cmake/package.cmake View File

@@ -0,0 +1,17 @@
list(APPEND CPACK_SOURCE_IGNORE_FILES
/\.git/
/\.gitignore
/\.github/
/\.tx/
/\.travis.yml
/_layouts/
/android/
/build/
/chromium_extension/
/data/
/docs/
/emscripten/
/fastlane/
/tools/
/vim/
)

+ 25
- 0
src/CMakeLists.txt View File

@@ -0,0 +1,25 @@
add_library(espeak-include INTERFACE)
target_include_directories(espeak-include INTERFACE include include/compat)

add_subdirectory(ucd-tools)
add_subdirectory(speechPlayer)
add_subdirectory(libespeak-ng)

add_executable(espeak-ng-bin espeak-ng.c)
set_target_properties(espeak-ng-bin PROPERTIES OUTPUT_NAME espeak-ng)
target_link_libraries(
espeak-ng-bin PRIVATE espeak-ng espeak-ng-config
)
if (MSVC)
target_sources(espeak-ng-bin PRIVATE compat/getopt.c)
endif()
if (NOT WIN32)
add_custom_target(
speak-ng ALL
${CMAKE_COMMAND} -E create_symlink espeak-ng ${CMAKE_CURRENT_BINARY_DIR}/speak-ng
COMMENT "Link espeak-ng to speak-ng"
DEPENDS espeak-ng-bin
)
endif()
install(TARGETS espeak-ng-bin)
install(DIRECTORY include/espeak include/espeak-ng TYPE INCLUDE)

+ 105
- 0
src/libespeak-ng/CMakeLists.txt View File

@@ -0,0 +1,105 @@
set(ESPEAK_CONFIG_DIR ${CMAKE_CURRENT_BINARY_DIR}/include)
set(ESPEAK_CONFIG_H ${ESPEAK_CONFIG_DIR}/config.h)
configure_file(config.h.in ${ESPEAK_CONFIG_H})

add_library(espeak-ng-config INTERFACE)
target_include_directories(espeak-ng-config INTERFACE ${ESPEAK_CONFIG_DIR})

add_library(espeak-ng
common.c
mnemonics.c
error.c
ieee80.c

compiledata.c
compiledict.c

dictionary.c
encoding.c
intonation.c
langopts.c
numbers.c
phoneme.c
phonemelist.c
readclause.c
setlengths.c
soundicon.c
spect.c
ssml.c
synthdata.c
synthesize.c
tr_languages.c
translate.c
translateword.c
voices.c
wavegen.c
speech.c

espeak_api.c
)

if (NOT MSVC)
target_compile_options(espeak-ng PRIVATE
"-fPIC"
"-fvisibility=hidden"
"-fno-exceptions"
"-fwrapv"

"-pedantic"

"-Wunused-parameter"
"-Wunused"
"-Wuninitialized"
"-Wreturn-type"
"-Wmissing-prototypes"
"-Wint-conversion"
"-Wimplicit"
)
endif()
target_compile_definitions(espeak-ng PRIVATE "LIBESPEAK_NG_EXPORT=1")
if (NOT BUILD_SHARED_LIBS)
target_compile_definitions(espeak-ng INTERFACE "LIBESPEAK_NG_EXPORT=1")
endif()

if (USE_ASYNC)
target_sources(espeak-ng PRIVATE
event.c
fifo.c
espeak_command.c
)
endif(USE_ASYNC)

if (USE_MBROLA)
target_sources(espeak-ng PRIVATE
mbrowrap.c
compilembrola.c
synth_mbrola.c
)
endif(USE_MBROLA)

if (USE_KLATT)
target_sources(espeak-ng PRIVATE klatt.c)
endif(USE_KLATT)

if (USE_SPEECHPLAYER)
target_sources(espeak-ng PRIVATE sPlayer.c)
target_link_libraries(espeak-ng PRIVATE speechPlayer)
endif(USE_SPEECHPLAYER)

if (HAVE_LIBSONIC AND USE_LIBSONIC)
target_link_libraries(espeak-ng PRIVATE ${SONIC_LIB})
target_include_directories(espeak-ng PRIVATE ${SONIC_INC})
endif()

if (HAVE_LIBPCAUDIO AND USE_LIBPCAUDIO)
target_link_libraries(espeak-ng PRIVATE ${PCAUDIO_LIB})
target_include_directories(espeak-ng PRIVATE ${PCAUDIO_INC})
endif()

target_link_libraries(espeak-ng PRIVATE espeak-ng-config ucd)
if (NOT MSVC)
target_link_libraries(espeak-ng PRIVATE m)
endif()
target_link_libraries(espeak-ng PUBLIC espeak-include)

install(TARGETS espeak-ng LIBRARY)

+ 10
- 0
src/libespeak-ng/config.h.in View File

@@ -0,0 +1,10 @@
#cmakedefine01 HAVE_MKSTEMP

#cmakedefine01 USE_ASYNC
#cmakedefine01 USE_KLATT
#cmakedefine01 USE_LIBPCAUDIO
#cmakedefine01 USE_LIBSONIC
#cmakedefine01 USE_MBROLA
#cmakedefine01 USE_SPEECHPLAYER

#define PACKAGE_VERSION "${PROJECT_VERSION}"

+ 10
- 0
src/speechPlayer/CMakeLists.txt View File

@@ -0,0 +1,10 @@
add_library(speechPlayer STATIC
src/frame.cpp
src/speechPlayer.cpp
src/speechWaveGenerator.cpp
)
target_include_directories(speechPlayer PUBLIC include)
if(NOT MSVC)
target_compile_options(speechPlayer PRIVATE "-fPIC")
endif()
install(TARGETS speechPlayer ARCHIVE)

+ 10
- 0
src/ucd-tools/CMakeLists.txt View File

@@ -0,0 +1,10 @@
add_library(ucd STATIC
src/case.c
src/categories.c
src/ctype.c
src/proplist.c
src/scripts.c
src/tostring.c
)
target_include_directories(ucd PUBLIC src/include)
install(TARGETS ucd ARCHIVE)

+ 73
- 0
tests/CMakeLists.txt View File

@@ -0,0 +1,73 @@
include(CTest)

list(APPEND _binary_tests)

macro(compiled_test _test_name)
add_executable(test_${_test_name}
$<TARGET_OBJECTS:espeak-ng>
${_test_name}.c
)
target_link_libraries(test_${_test_name} PRIVATE
$<TARGET_PROPERTY:espeak-ng,LINK_LIBRARIES>
)
target_include_directories(
test_${_test_name} PRIVATE
$<TARGET_PROPERTY:espeak-ng,SOURCE_DIR>
$<TARGET_PROPERTY:espeak-ng,SOURCE_DIR>/include/compat
$<TARGET_PROPERTY:espeak-ng,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:espeak-ng-config,INTERFACE_INCLUDE_DIRECTORIES>
)
add_dependencies(test_${_test_name} data)
add_test(
NAME ${_test_name}
COMMAND ${ESPEAK_RUN_ENV} $<TARGET_FILE:test_${_test_name}>
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/..
)
list(APPEND _binary_tests test_${_test_name})
endmacro(compiled_test)

find_program(SHELL bash)

macro(shell_test _test_name)
add_test(
NAME ${_test_name}
COMMAND ${ESPEAK_RUN_ENV} ESPEAK_BIN=$<TARGET_FILE:espeak-ng-bin> ${SHELL} ${CMAKE_CURRENT_SOURCE_DIR}/${_test_name}.test
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/..
)
endmacro(shell_test)

compiled_test(api)
compiled_test(encoding)
compiled_test(ieee80)
compiled_test(readclause)

if (SHELL AND UNIX)

shell_test(bom)
shell_test(non-executable-files-with-executable-bit)

shell_test(cmd_options)
shell_test(dictionary)
shell_test(language-numbers-cardinal)
shell_test(language-numbers-ordinal)
shell_test(language-phonemes)
shell_test(language-pronunciation)
shell_test(language-replace)
shell_test(ssml)
shell_test(translate)
shell_test(variants)
shell_test(voices)

# shell_test(windows-data)
# shell_test(windows-installer)

if (USE_KLATT)
shell_test(klatt)
endif()
if (USE_MBROLA)
shell_test(mbrola)
endif()

endif()

add_custom_target(tests DEPENDS ${_binary_tests})

+ 2
- 2
tests/bom.test View File

@@ -8,7 +8,8 @@ echo -n "testing for Byte Order Marks in source files ... "
# TODO checking for other encodings (e.g. UTF-16, UTF-32, UTF-7) needs more elaborate search,
# otherwise it shows many false positives

grep -ErlI $'\xEF\xBB\xBF' * | tee tests/bom.check >/dev/null # UTF-8
cd $(dirname $0)/..
grep -ErlI $'\xEF\xBB\xBF' * | grep -v '^build/' | tee tests/bom.check >/dev/null # UTF-8

if [ -s tests/bom.check ] ; then
echo "found:"
@@ -19,4 +20,3 @@ else
echo "none found"
true
fi


+ 1
- 1
tests/language-phonemes.test View File

@@ -8,7 +8,7 @@ is_hash
# read column 5 (File) of espeak-ng --voices, skip the directory
echo "checking if all supported languages have phoneme tests ..."
for lang in $(ESPEAK_DATA_PATH=`pwd` LD_LIBRARY_PATH=src:${LD_LIBRARY_PATH} src/espeak-ng --voices | awk '{print $5}' | cut -d "/" -f 2-2 | tail -n+2);
do if ! grep -q "test_phwav $lang" tests/language-phonemes.test
do if ! grep -q "test_phwav $lang" $0
then
echo "$lang missing a phoneme test in tests/language-phonemes.test";
exit 1;

+ 2
- 1
tests/non-executable-files-with-executable-bit.test View File

@@ -2,8 +2,10 @@

echo -n "testing files for executable bits that shouldn't be executable ... "

cd $(dirname $0)/..
find * -executable -type f | \
grep -vE "compile|config\.(guess|status|sub)|configure|depcomp|install-sh|libtool|missing" | # Ignore autotools output \
grep -vE "build" | # Ignore cmake output \
grep -vE ".*\.test|tests/common|src(/\.libs)?/(e?speak-ng|.*\.so\..*)|src/\.libs/lt-espeak-ng|android" | # Ignore built programs and libraries \
grep -vE ".*\.sh|tools/emoji" | # Ignore helper scripts \
grep -vE "src/ucd-tools/tools/(.*\.py|mkencodingtable)" | # Ignore ucd-tools helper scripts \
@@ -21,4 +23,3 @@ else
echo "none found"
true
fi


+ 2
- 2
tests/ssml.test View File

@@ -36,8 +36,8 @@ test_ssml() {
diff expected.txt actual.txt || exit 1
}

for i in `ls tests/ssml/*.ssml` ; do test_ssml $i; done
for i in `ls tests/ssml/*.ssml2` ; do test_ssml $i punct; done
for i in `dirname $0`/ssml/*.ssml ; do test_ssml $i; done
for i in `dirname $0`/ssml/*.ssml2 ; do test_ssml $i punct; done

test_ssml_audio "<prosody>" 88fccb35536158f25f4ae44a03fb005fef95c99b "<speak><prosody rate=\"x-slow\" pitch=\"low\"> Slow and low </prosody><prosody rate=\"x-fast\" pitch=\"x-high\"> Fast and high.</prosody></speak>"
# #410 is a bug in SSML. Sentence termination causes prosody stack to misfunction.

Loading…
Cancel
Save