Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

绑定到外部库

模块

The Summator example in 自定义 C++ 模块 is great for small, custom modules, but what if you want to use a larger, external library? Let's look at an example using Festival, a speech synthesis (text-to-speech) library written in C++.

要绑定到外部库, 请设置类似于Summator示例的模块目录:

godot/modules/tts/

Next, you will create a header file with a TTS class:

/* tts.h */

#ifndef GODOT_TTS_H
#define GODOT_TTS_H

#include "core/object/ref_counted.h"

class TTS : public RefCounted {
    GDCLASS(TTS, RefCounted);

protected:
    static void _bind_methods();

public:
    bool say_text(String p_txt);

    TTS();
};

#endif // GODOT_TTS_H

然后你将添加cpp文件.

/* tts.cpp */

#include "tts.h"

#include <festival.h>

bool TTS::say_text(String p_txt) {

    //convert Godot String to Godot CharString to C string
    return festival_say_text(p_txt.ascii().get_data());
}

void TTS::_bind_methods() {

    ClassDB::bind_method(D_METHOD("say_text", "txt"), &TTS::say_text);
}

TTS::TTS() {
    festival_initialize(true, 210000); //not the best way to do it as this should only ever be called once.
}

和以前一样, 需要以某种方式注册新类, 因此还需要创建两个文件:

register_types.h
register_types.cpp

重要

这些文件必须在你的模块的顶层文件夹中( SCsubconfig.py 文件旁边), 这样模块才能被正确注册.

这些文件应包含以下内容:

/* register_types.h */

void initialize_tts_module(ModuleInitializationLevel p_level);
void uninitialize_tts_module(ModuleInitializationLevel p_level);
/* yes, the word in the middle must be the same as the module folder name */
/* register_types.cpp */

#include "register_types.h"

#include "core/object/class_db.h"
#include "tts.h"

void initialize_tts_module(ModuleInitializationLevel p_level) {
    if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
        return;
    }
    ClassDB::register_class<TTS>();
}

void uninitialize_tts_module(ModuleInitializationLevel p_level) {
    // Nothing to do here in this example.
}

接下来, 需要创建一个 SCsub 文件, 以便构建系统编译此模块:

# SCsub

Import('env')

env_tts = env.Clone()
env_tts.add_source_files(env.modules_sources, "*.cpp") # Add all cpp files to the build

你需要在自己的机器上安装该外部库才能获取 .a 库文件。至于如何在你的操作系统中一步步安装,请参考该库的官方文档。作为参考,我们这里包含了用来在 Linux 下安装命令。

sudo apt-get install festival festival-dev <-- Installs festival and speech_tools libraries
apt-cache search festvox-* <-- Displays list of voice packages
sudo apt-get install festvox-don festvox-rablpc16k festvox-kallpc16k festvox-kdlpc16k <-- Installs voices

重要

Festival使用的声音(以及任何其他潜在的外部/第三方资源)都有不同的许可证和使用条款;其中一些(如果不是大多数)可能会对Godot产生问题, 即使Festival库本身是与MIT许可证兼容. 请务必检查许可证和使用条款.

外部库也需要被安装到你的模块之中,这样编译器就可以访问到源代码,保持模块独立于外界环境。可以使用如下的 git 命令从 modules/tts/ 目录安装 festival 和 speech_tools:

git clone https://github.com/festvox/festival
git clone https://github.com/festvox/speech_tools

如果不希望将外部仓库的源文件提交到你的仓库中,你可以通过将它们添加为子模块(从 modules/tts/ 目录中)来链接它们,如下所示:

git submodule add https://github.com/festvox/festival
git submodule add https://github.com/festvox/speech_tools

重要

Please note that Git submodules are not used in the Godot repository. If you are developing a module to be merged into the main Godot repository, you should not use submodules. If your module doesn't get merged in, you can always try to implement the external library as a GDExtension.

要添加供编译器查看的包含目录, 可以将其追加到环境的路径中:

# These paths are relative to /modules/tts/
env_tts.Append(CPPPATH=["speech_tools/include", "festival/src/include"])

# LIBPATH and LIBS need to be set on the real "env" (not the clone)
# to link the specified libraries to the Godot executable.

# This is a path relative to /modules/tts/ where your .a libraries reside.
# If you are compiling the module externally (not in the godot source tree),
# these will need to be full paths.
env.Append(LIBPATH=['libpath'])

# Check with the documentation of the external library to see which library
# files should be included/linked.
env.Append(LIBS=['Festival', 'estools', 'estbase', 'eststring'])

如果要在构建模块时添加自定义编译器标志, 则需要首先克隆 env, 这样它就不会将这些标志添加到整个Godot构建中(这可能会导致错误). 带有自定义标志的示例 SCsub:

# SCsub

Import('env')

env_tts = env.Clone()
env_tts.add_source_files(env.modules_sources, "*.cpp")
    # Append CCFLAGS flags for both C and C++ code.
env_tts.Append(CCFLAGS=['-O2'])
# If you need to, you can:
# - Append CFLAGS for C code only.
# - Append CXXFLAGS for C++ code only.

最终模块应如下所示:

godot/modules/tts/festival/
godot/modules/tts/libpath/libestbase.a
godot/modules/tts/libpath/libestools.a
godot/modules/tts/libpath/libeststring.a
godot/modules/tts/libpath/libFestival.a
godot/modules/tts/speech_tools/
godot/modules/tts/config.py
godot/modules/tts/tts.h
godot/modules/tts/tts.cpp
godot/modules/tts/register_types.h
godot/modules/tts/register_types.cpp
godot/modules/tts/SCsub

使用模块

现在, 你可以通过任何脚本使用新创建的模块:

var t = TTS.new()
var script = "Hello world. This is a test!"
var is_spoken = t.say_text(script)
print('is_spoken: ', is_spoken)

如果说出文本, 输出将是 is_spoken:True .