正在显示
11 个修改的文件
包含
1167 行增加
和
0 行删除
.gitignore
0 → 100644
| 1 | +build |
CMakeLists.txt
0 → 100644
| 1 | +cmake_minimum_required(VERSION 3.8 FATAL_ERROR) | ||
| 2 | +project(sherpa-onnx) | ||
| 3 | + | ||
| 4 | +set(SHERPA_ONNX_VERSION "0.1") | ||
| 5 | + | ||
| 6 | +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") | ||
| 7 | +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") | ||
| 8 | +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") | ||
| 9 | + | ||
| 10 | +set(CMAKE_SKIP_BUILD_RPATH FALSE) | ||
| 11 | +set(BUILD_RPATH_USE_ORIGIN TRUE) | ||
| 12 | +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) | ||
| 13 | + | ||
| 14 | +if(NOT APPLE) | ||
| 15 | + set(SHERPA_ONNX_RPATH_ORIGIN "$ORIGIN") | ||
| 16 | +else() | ||
| 17 | + set(SHERPA_ONNX_RPATH_ORIGIN "@loader_path") | ||
| 18 | +endif() | ||
| 19 | + | ||
| 20 | +set(CMAKE_INSTALL_RPATH ${SHERPA_ONNX_RPATH_ORIGIN}) | ||
| 21 | +set(CMAKE_BUILD_RPATH ${SHERPA_ONNX_RPATH_ORIGIN}) | ||
| 22 | + | ||
| 23 | +set(BUILD_SHARED_LIBS ON) | ||
| 24 | +if(WIN32) | ||
| 25 | + message(STATUS "Set BUILD_SHARED_LIBS to OFF for Windows") | ||
| 26 | + set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) | ||
| 27 | +endif() | ||
| 28 | + | ||
| 29 | +if(NOT CMAKE_BUILD_TYPE) | ||
| 30 | + message(STATUS "No CMAKE_BUILD_TYPE given, default to Release") | ||
| 31 | + set(CMAKE_BUILD_TYPE Release) | ||
| 32 | +endif() | ||
| 33 | +message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") | ||
| 34 | + | ||
| 35 | +set(CMAKE_CXX_STANDARD 14 CACHE STRING "The C++ version to be used.") | ||
| 36 | +set(CMAKE_CXX_EXTENSIONS OFF) | ||
| 37 | + | ||
| 38 | +list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules) | ||
| 39 | +list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) | ||
| 40 | + | ||
| 41 | +include(cmake/kaldi-native-fbank.cmake) | ||
| 42 | + | ||
| 43 | +add_subdirectory(sherpa-onnx) |
| @@ -4,3 +4,16 @@ See <https://github.com/k2-fsa/sherpa> | @@ -4,3 +4,16 @@ See <https://github.com/k2-fsa/sherpa> | ||
| 4 | 4 | ||
| 5 | This repo uses [onnxruntime](https://github.com/microsoft/onnxruntime) and | 5 | This repo uses [onnxruntime](https://github.com/microsoft/onnxruntime) and |
| 6 | does not depend on libtorch. | 6 | does not depend on libtorch. |
| 7 | + | ||
| 8 | +# Usage | ||
| 9 | + | ||
| 10 | +```bash | ||
| 11 | +git clone https://github.com/k2-fsa/sherpa-onnx | ||
| 12 | +cd sherpa-onnx | ||
| 13 | +mkdir build | ||
| 14 | +cd build | ||
| 15 | +cmake .. | ||
| 16 | +make -j | ||
| 17 | + | ||
| 18 | +./bin/online-fbank-test | ||
| 19 | +``` |
cmake/Modules/FetchContent.cmake
0 → 100644
| 1 | +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying | ||
| 2 | +# file Copyright.txt or https://cmake.org/licensing for details. | ||
| 3 | + | ||
| 4 | +#[=======================================================================[.rst: | ||
| 5 | +FetchContent | ||
| 6 | +------------------ | ||
| 7 | + | ||
| 8 | +.. only:: html | ||
| 9 | + | ||
| 10 | + .. contents:: | ||
| 11 | + | ||
| 12 | +Overview | ||
| 13 | +^^^^^^^^ | ||
| 14 | + | ||
| 15 | +This module enables populating content at configure time via any method | ||
| 16 | +supported by the :module:`ExternalProject` module. Whereas | ||
| 17 | +:command:`ExternalProject_Add` downloads at build time, the | ||
| 18 | +``FetchContent`` module makes content available immediately, allowing the | ||
| 19 | +configure step to use the content in commands like :command:`add_subdirectory`, | ||
| 20 | +:command:`include` or :command:`file` operations. | ||
| 21 | + | ||
| 22 | +Content population details would normally be defined separately from the | ||
| 23 | +command that performs the actual population. Projects should also | ||
| 24 | +check whether the content has already been populated somewhere else in the | ||
| 25 | +project hierarchy. Typical usage would look something like this: | ||
| 26 | + | ||
| 27 | +.. code-block:: cmake | ||
| 28 | + | ||
| 29 | + FetchContent_Declare( | ||
| 30 | + googletest | ||
| 31 | + GIT_REPOSITORY https://github.com/google/googletest.git | ||
| 32 | + GIT_TAG release-1.8.0 | ||
| 33 | + ) | ||
| 34 | + | ||
| 35 | + FetchContent_GetProperties(googletest) | ||
| 36 | + if(NOT googletest_POPULATED) | ||
| 37 | + FetchContent_Populate(googletest) | ||
| 38 | + add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR}) | ||
| 39 | + endif() | ||
| 40 | + | ||
| 41 | +When using the above pattern with a hierarchical project arrangement, | ||
| 42 | +projects at higher levels in the hierarchy are able to define or override | ||
| 43 | +the population details of content specified anywhere lower in the project | ||
| 44 | +hierarchy. The ability to detect whether content has already been | ||
| 45 | +populated ensures that even if multiple child projects want certain content | ||
| 46 | +to be available, the first one to populate it wins. The other child project | ||
| 47 | +can simply make use of the already available content instead of repeating | ||
| 48 | +the population for itself. See the | ||
| 49 | +:ref:`Examples <fetch-content-examples>` section which demonstrates | ||
| 50 | +this scenario. | ||
| 51 | + | ||
| 52 | +The ``FetchContent`` module also supports defining and populating | ||
| 53 | +content in a single call, with no check for whether the content has been | ||
| 54 | +populated elsewhere in the project already. This is a more low level | ||
| 55 | +operation and would not normally be the way the module is used, but it is | ||
| 56 | +sometimes useful as part of implementing some higher level feature or to | ||
| 57 | +populate some content in CMake's script mode. | ||
| 58 | + | ||
| 59 | + | ||
| 60 | +Declaring Content Details | ||
| 61 | +^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 62 | + | ||
| 63 | +.. command:: FetchContent_Declare | ||
| 64 | + | ||
| 65 | + .. code-block:: cmake | ||
| 66 | + | ||
| 67 | + FetchContent_Declare(<name> <contentOptions>...) | ||
| 68 | + | ||
| 69 | + The ``FetchContent_Declare()`` function records the options that describe | ||
| 70 | + how to populate the specified content, but if such details have already | ||
| 71 | + been recorded earlier in this project (regardless of where in the project | ||
| 72 | + hierarchy), this and all later calls for the same content ``<name>`` are | ||
| 73 | + ignored. This "first to record, wins" approach is what allows hierarchical | ||
| 74 | + projects to have parent projects override content details of child projects. | ||
| 75 | + | ||
| 76 | + The content ``<name>`` can be any string without spaces, but good practice | ||
| 77 | + would be to use only letters, numbers and underscores. The name will be | ||
| 78 | + treated case-insensitively and it should be obvious for the content it | ||
| 79 | + represents, often being the name of the child project or the value given | ||
| 80 | + to its top level :command:`project` command (if it is a CMake project). | ||
| 81 | + For well-known public projects, the name should generally be the official | ||
| 82 | + name of the project. Choosing an unusual name makes it unlikely that other | ||
| 83 | + projects needing that same content will use the same name, leading to | ||
| 84 | + the content being populated multiple times. | ||
| 85 | + | ||
| 86 | + The ``<contentOptions>`` can be any of the download or update/patch options | ||
| 87 | + that the :command:`ExternalProject_Add` command understands. The configure, | ||
| 88 | + build, install and test steps are explicitly disabled and therefore options | ||
| 89 | + related to them will be ignored. In most cases, ``<contentOptions>`` will | ||
| 90 | + just be a couple of options defining the download method and method-specific | ||
| 91 | + details like a commit tag or archive hash. For example: | ||
| 92 | + | ||
| 93 | + .. code-block:: cmake | ||
| 94 | + | ||
| 95 | + FetchContent_Declare( | ||
| 96 | + googletest | ||
| 97 | + GIT_REPOSITORY https://github.com/google/googletest.git | ||
| 98 | + GIT_TAG release-1.8.0 | ||
| 99 | + ) | ||
| 100 | + | ||
| 101 | + FetchContent_Declare( | ||
| 102 | + myCompanyIcons | ||
| 103 | + URL https://intranet.mycompany.com/assets/iconset_1.12.tar.gz | ||
| 104 | + URL_HASH 5588a7b18261c20068beabfb4f530b87 | ||
| 105 | + ) | ||
| 106 | + | ||
| 107 | + FetchContent_Declare( | ||
| 108 | + myCompanyCertificates | ||
| 109 | + SVN_REPOSITORY svn+ssh://svn.mycompany.com/srv/svn/trunk/certs | ||
| 110 | + SVN_REVISION -r12345 | ||
| 111 | + ) | ||
| 112 | + | ||
| 113 | +Populating The Content | ||
| 114 | +^^^^^^^^^^^^^^^^^^^^^^ | ||
| 115 | + | ||
| 116 | +.. command:: FetchContent_Populate | ||
| 117 | + | ||
| 118 | + .. code-block:: cmake | ||
| 119 | + | ||
| 120 | + FetchContent_Populate( <name> ) | ||
| 121 | + | ||
| 122 | + In most cases, the only argument given to ``FetchContent_Populate()`` is the | ||
| 123 | + ``<name>``. When used this way, the command assumes the content details have | ||
| 124 | + been recorded by an earlier call to :command:`FetchContent_Declare`. The | ||
| 125 | + details are stored in a global property, so they are unaffected by things | ||
| 126 | + like variable or directory scope. Therefore, it doesn't matter where in the | ||
| 127 | + project the details were previously declared, as long as they have been | ||
| 128 | + declared before the call to ``FetchContent_Populate()``. Those saved details | ||
| 129 | + are then used to construct a call to :command:`ExternalProject_Add` in a | ||
| 130 | + private sub-build to perform the content population immediately. The | ||
| 131 | + implementation of ``ExternalProject_Add()`` ensures that if the content has | ||
| 132 | + already been populated in a previous CMake run, that content will be reused | ||
| 133 | + rather than repopulating them again. For the common case where population | ||
| 134 | + involves downloading content, the cost of the download is only paid once. | ||
| 135 | + | ||
| 136 | + An internal global property records when a particular content population | ||
| 137 | + request has been processed. If ``FetchContent_Populate()`` is called more | ||
| 138 | + than once for the same content name within a configure run, the second call | ||
| 139 | + will halt with an error. Projects can and should check whether content | ||
| 140 | + population has already been processed with the | ||
| 141 | + :command:`FetchContent_GetProperties` command before calling | ||
| 142 | + ``FetchContent_Populate()``. | ||
| 143 | + | ||
| 144 | + ``FetchContent_Populate()`` will set three variables in the scope of the | ||
| 145 | + caller; ``<lcName>_POPULATED``, ``<lcName>_SOURCE_DIR`` and | ||
| 146 | + ``<lcName>_BINARY_DIR``, where ``<lcName>`` is the lowercased ``<name>``. | ||
| 147 | + ``<lcName>_POPULATED`` will always be set to ``True`` by the call. | ||
| 148 | + ``<lcName>_SOURCE_DIR`` is the location where the | ||
| 149 | + content can be found upon return (it will have already been populated), while | ||
| 150 | + ``<lcName>_BINARY_DIR`` is a directory intended for use as a corresponding | ||
| 151 | + build directory. The main use case for the two directory variables is to | ||
| 152 | + call :command:`add_subdirectory` immediately after population, i.e.: | ||
| 153 | + | ||
| 154 | + .. code-block:: cmake | ||
| 155 | + | ||
| 156 | + FetchContent_Populate(FooBar ...) | ||
| 157 | + add_subdirectory(${foobar_SOURCE_DIR} ${foobar_BINARY_DIR}) | ||
| 158 | + | ||
| 159 | + The values of the three variables can also be retrieved from anywhere in the | ||
| 160 | + project hierarchy using the :command:`FetchContent_GetProperties` command. | ||
| 161 | + | ||
| 162 | + A number of cache variables influence the behavior of all content population | ||
| 163 | + performed using details saved from a :command:`FetchContent_Declare` call: | ||
| 164 | + | ||
| 165 | + ``FETCHCONTENT_BASE_DIR`` | ||
| 166 | + In most cases, the saved details do not specify any options relating to the | ||
| 167 | + directories to use for the internal sub-build, final source and build areas. | ||
| 168 | + It is generally best to leave these decisions up to the ``FetchContent`` | ||
| 169 | + module to handle on the project's behalf. The ``FETCHCONTENT_BASE_DIR`` | ||
| 170 | + cache variable controls the point under which all content population | ||
| 171 | + directories are collected, but in most cases developers would not need to | ||
| 172 | + change this. The default location is ``${CMAKE_BINARY_DIR}/_deps``, but if | ||
| 173 | + developers change this value, they should aim to keep the path short and | ||
| 174 | + just below the top level of the build tree to avoid running into path | ||
| 175 | + length problems on Windows. | ||
| 176 | + | ||
| 177 | + ``FETCHCONTENT_QUIET`` | ||
| 178 | + The logging output during population can be quite verbose, making the | ||
| 179 | + configure stage quite noisy. This cache option (``ON`` by default) hides | ||
| 180 | + all population output unless an error is encountered. If experiencing | ||
| 181 | + problems with hung downloads, temporarily switching this option off may | ||
| 182 | + help diagnose which content population is causing the issue. | ||
| 183 | + | ||
| 184 | + ``FETCHCONTENT_FULLY_DISCONNECTED`` | ||
| 185 | + When this option is enabled, no attempt is made to download or update | ||
| 186 | + any content. It is assumed that all content has already been populated in | ||
| 187 | + a previous run or the source directories have been pointed at existing | ||
| 188 | + contents the developer has provided manually (using options described | ||
| 189 | + further below). When the developer knows that no changes have been made to | ||
| 190 | + any content details, turning this option ``ON`` can significantly speed up | ||
| 191 | + the configure stage. It is ``OFF`` by default. | ||
| 192 | + | ||
| 193 | + ``FETCHCONTENT_UPDATES_DISCONNECTED`` | ||
| 194 | + This is a less severe download/update control compared to | ||
| 195 | + ``FETCHCONTENT_FULLY_DISCONNECTED``. Instead of bypassing all download and | ||
| 196 | + update logic, the ``FETCHCONTENT_UPDATES_DISCONNECTED`` only disables the | ||
| 197 | + update stage. Therefore, if content has not been downloaded previously, | ||
| 198 | + it will still be downloaded when this option is enabled. This can speed up | ||
| 199 | + the configure stage, but not as much as | ||
| 200 | + ``FETCHCONTENT_FULLY_DISCONNECTED``. It is ``OFF`` by default. | ||
| 201 | + | ||
| 202 | + In addition to the above cache variables, the following cache variables are | ||
| 203 | + also defined for each content name (``<ucName>`` is the uppercased value of | ||
| 204 | + ``<name>``): | ||
| 205 | + | ||
| 206 | + ``FETCHCONTENT_SOURCE_DIR_<ucName>`` | ||
| 207 | + If this is set, no download or update steps are performed for the specified | ||
| 208 | + content and the ``<lcName>_SOURCE_DIR`` variable returned to the caller is | ||
| 209 | + pointed at this location. This gives developers a way to have a separate | ||
| 210 | + checkout of the content that they can modify freely without interference | ||
| 211 | + from the build. The build simply uses that existing source, but it still | ||
| 212 | + defines ``<lcName>_BINARY_DIR`` to point inside its own build area. | ||
| 213 | + Developers are strongly encouraged to use this mechanism rather than | ||
| 214 | + editing the sources populated in the default location, as changes to | ||
| 215 | + sources in the default location can be lost when content population details | ||
| 216 | + are changed by the project. | ||
| 217 | + | ||
| 218 | + ``FETCHCONTENT_UPDATES_DISCONNECTED_<ucName>`` | ||
| 219 | + This is the per-content equivalent of | ||
| 220 | + ``FETCHCONTENT_UPDATES_DISCONNECTED``. If the global option or this option | ||
| 221 | + is ``ON``, then updates will be disabled for the named content. | ||
| 222 | + Disabling updates for individual content can be useful for content whose | ||
| 223 | + details rarely change, while still leaving other frequently changing | ||
| 224 | + content with updates enabled. | ||
| 225 | + | ||
| 226 | + | ||
| 227 | + The ``FetchContent_Populate()`` command also supports a syntax allowing the | ||
| 228 | + content details to be specified directly rather than using any saved | ||
| 229 | + details. This is more low-level and use of this form is generally to be | ||
| 230 | + avoided in favour of using saved content details as outlined above. | ||
| 231 | + Nevertheless, in certain situations it can be useful to invoke the content | ||
| 232 | + population as an isolated operation (typically as part of implementing some | ||
| 233 | + other higher level feature or when using CMake in script mode): | ||
| 234 | + | ||
| 235 | + .. code-block:: cmake | ||
| 236 | + | ||
| 237 | + FetchContent_Populate( <name> | ||
| 238 | + [QUIET] | ||
| 239 | + [SUBBUILD_DIR <subBuildDir>] | ||
| 240 | + [SOURCE_DIR <srcDir>] | ||
| 241 | + [BINARY_DIR <binDir>] | ||
| 242 | + ... | ||
| 243 | + ) | ||
| 244 | + | ||
| 245 | + This form has a number of key differences to that where only ``<name>`` is | ||
| 246 | + provided: | ||
| 247 | + | ||
| 248 | + - All required population details are assumed to have been provided directly | ||
| 249 | + in the call to ``FetchContent_Populate()``. Any saved details for | ||
| 250 | + ``<name>`` are ignored. | ||
| 251 | + - No check is made for whether content for ``<name>`` has already been | ||
| 252 | + populated. | ||
| 253 | + - No global property is set to record that the population has occurred. | ||
| 254 | + - No global properties record the source or binary directories used for the | ||
| 255 | + populated content. | ||
| 256 | + - The ``FETCHCONTENT_FULLY_DISCONNECTED`` and | ||
| 257 | + ``FETCHCONTENT_UPDATES_DISCONNECTED`` cache variables are ignored. | ||
| 258 | + | ||
| 259 | + The ``<lcName>_SOURCE_DIR`` and ``<lcName>_BINARY_DIR`` variables are still | ||
| 260 | + returned to the caller, but since these locations are not stored as global | ||
| 261 | + properties when this form is used, they are only available to the calling | ||
| 262 | + scope and below rather than the entire project hierarchy. No | ||
| 263 | + ``<lcName>_POPULATED`` variable is set in the caller's scope with this form. | ||
| 264 | + | ||
| 265 | + The supported options for ``FetchContent_Populate()`` are the same as those | ||
| 266 | + for :command:`FetchContent_Declare()`. Those few options shown just | ||
| 267 | + above are either specific to ``FetchContent_Populate()`` or their behavior is | ||
| 268 | + slightly modified from how :command:`ExternalProject_Add` treats them. | ||
| 269 | + | ||
| 270 | + ``QUIET`` | ||
| 271 | + The ``QUIET`` option can be given to hide the output associated with | ||
| 272 | + populating the specified content. If the population fails, the output will | ||
| 273 | + be shown regardless of whether this option was given or not so that the | ||
| 274 | + cause of the failure can be diagnosed. The global ``FETCHCONTENT_QUIET`` | ||
| 275 | + cache variable has no effect on ``FetchContent_Populate()`` calls where the | ||
| 276 | + content details are provided directly. | ||
| 277 | + | ||
| 278 | + ``SUBBUILD_DIR`` | ||
| 279 | + The ``SUBBUILD_DIR`` argument can be provided to change the location of the | ||
| 280 | + sub-build created to perform the population. The default value is | ||
| 281 | + ``${CMAKE_CURRENT_BINARY_DIR}/<lcName>-subbuild`` and it would be unusual | ||
| 282 | + to need to override this default. If a relative path is specified, it will | ||
| 283 | + be interpreted as relative to :variable:`CMAKE_CURRENT_BINARY_DIR`. | ||
| 284 | + | ||
| 285 | + ``SOURCE_DIR``, ``BINARY_DIR`` | ||
| 286 | + The ``SOURCE_DIR`` and ``BINARY_DIR`` arguments are supported by | ||
| 287 | + :command:`ExternalProject_Add`, but different default values are used by | ||
| 288 | + ``FetchContent_Populate()``. ``SOURCE_DIR`` defaults to | ||
| 289 | + ``${CMAKE_CURRENT_BINARY_DIR}/<lcName>-src`` and ``BINARY_DIR`` defaults to | ||
| 290 | + ``${CMAKE_CURRENT_BINARY_DIR}/<lcName>-build``. If a relative path is | ||
| 291 | + specified, it will be interpreted as relative to | ||
| 292 | + :variable:`CMAKE_CURRENT_BINARY_DIR`. | ||
| 293 | + | ||
| 294 | + In addition to the above explicit options, any other unrecognized options are | ||
| 295 | + passed through unmodified to :command:`ExternalProject_Add` to perform the | ||
| 296 | + download, patch and update steps. The following options are explicitly | ||
| 297 | + prohibited (they are disabled by the ``FetchContent_Populate()`` command): | ||
| 298 | + | ||
| 299 | + - ``CONFIGURE_COMMAND`` | ||
| 300 | + - ``BUILD_COMMAND`` | ||
| 301 | + - ``INSTALL_COMMAND`` | ||
| 302 | + - ``TEST_COMMAND`` | ||
| 303 | + | ||
| 304 | + If using ``FetchContent_Populate()`` within CMake's script mode, be aware | ||
| 305 | + that the implementation sets up a sub-build which therefore requires a CMake | ||
| 306 | + generator and build tool to be available. If these cannot be found by | ||
| 307 | + default, then the :variable:`CMAKE_GENERATOR` and/or | ||
| 308 | + :variable:`CMAKE_MAKE_PROGRAM` variables will need to be set appropriately | ||
| 309 | + on the command line invoking the script. | ||
| 310 | + | ||
| 311 | + | ||
| 312 | +Retrieve Population Properties | ||
| 313 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 314 | + | ||
| 315 | +.. command:: FetchContent_GetProperties | ||
| 316 | + | ||
| 317 | + When using saved content details, a call to :command:`FetchContent_Populate` | ||
| 318 | + records information in global properties which can be queried at any time. | ||
| 319 | + This information includes the source and binary directories associated with | ||
| 320 | + the content and also whether or not the content population has been processed | ||
| 321 | + during the current configure run. | ||
| 322 | + | ||
| 323 | + .. code-block:: cmake | ||
| 324 | + | ||
| 325 | + FetchContent_GetProperties( <name> | ||
| 326 | + [SOURCE_DIR <srcDirVar>] | ||
| 327 | + [BINARY_DIR <binDirVar>] | ||
| 328 | + [POPULATED <doneVar>] | ||
| 329 | + ) | ||
| 330 | + | ||
| 331 | + The ``SOURCE_DIR``, ``BINARY_DIR`` and ``POPULATED`` options can be used to | ||
| 332 | + specify which properties should be retrieved. Each option accepts a value | ||
| 333 | + which is the name of the variable in which to store that property. Most of | ||
| 334 | + the time though, only ``<name>`` is given, in which case the call will then | ||
| 335 | + set the same variables as a call to | ||
| 336 | + :command:`FetchContent_Populate(name) <FetchContent_Populate>`. This allows | ||
| 337 | + the following canonical pattern to be used, which ensures that the relevant | ||
| 338 | + variables will always be defined regardless of whether or not the population | ||
| 339 | + has been performed elsewhere in the project already: | ||
| 340 | + | ||
| 341 | + .. code-block:: cmake | ||
| 342 | + | ||
| 343 | + FetchContent_GetProperties(foobar) | ||
| 344 | + if(NOT foobar_POPULATED) | ||
| 345 | + FetchContent_Populate(foobar) | ||
| 346 | + | ||
| 347 | + # Set any custom variables, etc. here, then | ||
| 348 | + # populate the content as part of this build | ||
| 349 | + | ||
| 350 | + add_subdirectory(${foobar_SOURCE_DIR} ${foobar_BINARY_DIR}) | ||
| 351 | + endif() | ||
| 352 | + | ||
| 353 | + The above pattern allows other parts of the overall project hierarchy to | ||
| 354 | + re-use the same content and ensure that it is only populated once. | ||
| 355 | + | ||
| 356 | + | ||
| 357 | +.. _`fetch-content-examples`: | ||
| 358 | + | ||
| 359 | +Examples | ||
| 360 | +^^^^^^^^ | ||
| 361 | + | ||
| 362 | +Consider a project hierarchy where ``projA`` is the top level project and it | ||
| 363 | +depends on projects ``projB`` and ``projC``. Both ``projB`` and ``projC`` | ||
| 364 | +can be built standalone and they also both depend on another project | ||
| 365 | +``projD``. For simplicity, this example will assume that all four projects | ||
| 366 | +are available on a company git server. The ``CMakeLists.txt`` of each project | ||
| 367 | +might have sections like the following: | ||
| 368 | + | ||
| 369 | +*projA*: | ||
| 370 | + | ||
| 371 | +.. code-block:: cmake | ||
| 372 | + | ||
| 373 | + include(FetchContent) | ||
| 374 | + FetchContent_Declare( | ||
| 375 | + projB | ||
| 376 | + GIT_REPOSITORY git@mycompany.com/git/projB.git | ||
| 377 | + GIT_TAG 4a89dc7e24ff212a7b5167bef7ab079d | ||
| 378 | + ) | ||
| 379 | + FetchContent_Declare( | ||
| 380 | + projC | ||
| 381 | + GIT_REPOSITORY git@mycompany.com/git/projC.git | ||
| 382 | + GIT_TAG 4ad4016bd1d8d5412d135cf8ceea1bb9 | ||
| 383 | + ) | ||
| 384 | + FetchContent_Declare( | ||
| 385 | + projD | ||
| 386 | + GIT_REPOSITORY git@mycompany.com/git/projD.git | ||
| 387 | + GIT_TAG origin/integrationBranch | ||
| 388 | + ) | ||
| 389 | + | ||
| 390 | + FetchContent_GetProperties(projB) | ||
| 391 | + if(NOT projb_POPULATED) | ||
| 392 | + FetchContent_Populate(projB) | ||
| 393 | + add_subdirectory(${projb_SOURCE_DIR} ${projb_BINARY_DIR}) | ||
| 394 | + endif() | ||
| 395 | + | ||
| 396 | + FetchContent_GetProperties(projC) | ||
| 397 | + if(NOT projc_POPULATED) | ||
| 398 | + FetchContent_Populate(projC) | ||
| 399 | + add_subdirectory(${projc_SOURCE_DIR} ${projc_BINARY_DIR}) | ||
| 400 | + endif() | ||
| 401 | + | ||
| 402 | +*projB*: | ||
| 403 | + | ||
| 404 | +.. code-block:: cmake | ||
| 405 | + | ||
| 406 | + include(FetchContent) | ||
| 407 | + FetchContent_Declare( | ||
| 408 | + projD | ||
| 409 | + GIT_REPOSITORY git@mycompany.com/git/projD.git | ||
| 410 | + GIT_TAG 20b415f9034bbd2a2e8216e9a5c9e632 | ||
| 411 | + ) | ||
| 412 | + | ||
| 413 | + FetchContent_GetProperties(projD) | ||
| 414 | + if(NOT projd_POPULATED) | ||
| 415 | + FetchContent_Populate(projD) | ||
| 416 | + add_subdirectory(${projd_SOURCE_DIR} ${projd_BINARY_DIR}) | ||
| 417 | + endif() | ||
| 418 | + | ||
| 419 | + | ||
| 420 | +*projC*: | ||
| 421 | + | ||
| 422 | +.. code-block:: cmake | ||
| 423 | + | ||
| 424 | + include(FetchContent) | ||
| 425 | + FetchContent_Declare( | ||
| 426 | + projD | ||
| 427 | + GIT_REPOSITORY git@mycompany.com/git/projD.git | ||
| 428 | + GIT_TAG 7d9a17ad2c962aa13e2fbb8043fb6b8a | ||
| 429 | + ) | ||
| 430 | + | ||
| 431 | + FetchContent_GetProperties(projD) | ||
| 432 | + if(NOT projd_POPULATED) | ||
| 433 | + FetchContent_Populate(projD) | ||
| 434 | + add_subdirectory(${projd_SOURCE_DIR} ${projd_BINARY_DIR}) | ||
| 435 | + endif() | ||
| 436 | + | ||
| 437 | +A few key points should be noted in the above: | ||
| 438 | + | ||
| 439 | +- ``projB`` and ``projC`` define different content details for ``projD``, | ||
| 440 | + but ``projA`` also defines a set of content details for ``projD`` and | ||
| 441 | + because ``projA`` will define them first, the details from ``projB`` and | ||
| 442 | + ``projC`` will not be used. The override details defined by ``projA`` | ||
| 443 | + are not required to match either of those from ``projB`` or ``projC``, but | ||
| 444 | + it is up to the higher level project to ensure that the details it does | ||
| 445 | + define still make sense for the child projects. | ||
| 446 | +- While ``projA`` defined content details for ``projD``, it did not need | ||
| 447 | + to explicitly call ``FetchContent_Populate(projD)`` itself. Instead, it | ||
| 448 | + leaves that to a child project to do (in this case it will be ``projB`` | ||
| 449 | + since it is added to the build ahead of ``projC``). If ``projA`` needed to | ||
| 450 | + customize how the ``projD`` content was brought into the build as well | ||
| 451 | + (e.g. define some CMake variables before calling | ||
| 452 | + :command:`add_subdirectory` after populating), it would do the call to | ||
| 453 | + ``FetchContent_Populate()``, etc. just as it did for the ``projB`` and | ||
| 454 | + ``projC`` content. For higher level projects, it is usually enough to | ||
| 455 | + just define the override content details and leave the actual population | ||
| 456 | + to the child projects. This saves repeating the same thing at each level | ||
| 457 | + of the project hierarchy unnecessarily. | ||
| 458 | +- Even though ``projA`` is the top level project in this example, it still | ||
| 459 | + checks whether ``projB`` and ``projC`` have already been populated before | ||
| 460 | + going ahead to do those populations. This makes ``projA`` able to be more | ||
| 461 | + easily incorporated as a child of some other higher level project in the | ||
| 462 | + future if required. Always protect a call to | ||
| 463 | + :command:`FetchContent_Populate` with a check to | ||
| 464 | + :command:`FetchContent_GetProperties`, even in what may be considered a top | ||
| 465 | + level project at the time. | ||
| 466 | + | ||
| 467 | + | ||
| 468 | +The following example demonstrates how one might download and unpack a | ||
| 469 | +firmware tarball using CMake's :manual:`script mode <cmake(1)>`. The call to | ||
| 470 | +:command:`FetchContent_Populate` specifies all the content details and the | ||
| 471 | +unpacked firmware will be placed in a ``firmware`` directory below the | ||
| 472 | +current working directory. | ||
| 473 | + | ||
| 474 | +*getFirmware.cmake*: | ||
| 475 | + | ||
| 476 | +.. code-block:: cmake | ||
| 477 | + | ||
| 478 | + # NOTE: Intended to be run in script mode with cmake -P | ||
| 479 | + include(FetchContent) | ||
| 480 | + FetchContent_Populate( | ||
| 481 | + firmware | ||
| 482 | + URL https://mycompany.com/assets/firmware-1.23-arm.tar.gz | ||
| 483 | + URL_HASH MD5=68247684da89b608d466253762b0ff11 | ||
| 484 | + SOURCE_DIR firmware | ||
| 485 | + ) | ||
| 486 | + | ||
| 487 | +#]=======================================================================] | ||
| 488 | + | ||
| 489 | + | ||
| 490 | +set(__FetchContent_privateDir "${CMAKE_CURRENT_LIST_DIR}/FetchContent") | ||
| 491 | + | ||
| 492 | +#======================================================================= | ||
| 493 | +# Recording and retrieving content details for later population | ||
| 494 | +#======================================================================= | ||
| 495 | + | ||
| 496 | +# Internal use, projects must not call this directly. It is | ||
| 497 | +# intended for use by FetchContent_Declare() only. | ||
| 498 | +# | ||
| 499 | +# Sets a content-specific global property (not meant for use | ||
| 500 | +# outside of functions defined here in this file) which can later | ||
| 501 | +# be retrieved using __FetchContent_getSavedDetails() with just the | ||
| 502 | +# same content name. If there is already a value stored in the | ||
| 503 | +# property, it is left unchanged and this call has no effect. | ||
| 504 | +# This allows parent projects to define the content details, | ||
| 505 | +# overriding anything a child project may try to set (properties | ||
| 506 | +# are not cached between runs, so the first thing to set it in a | ||
| 507 | +# build will be in control). | ||
| 508 | +function(__FetchContent_declareDetails contentName) | ||
| 509 | + | ||
| 510 | + string(TOLOWER ${contentName} contentNameLower) | ||
| 511 | + set(propertyName "_FetchContent_${contentNameLower}_savedDetails") | ||
| 512 | + get_property(alreadyDefined GLOBAL PROPERTY ${propertyName} DEFINED) | ||
| 513 | + if(NOT alreadyDefined) | ||
| 514 | + define_property(GLOBAL PROPERTY ${propertyName} | ||
| 515 | + BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()" | ||
| 516 | + FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}" | ||
| 517 | + ) | ||
| 518 | + set_property(GLOBAL PROPERTY ${propertyName} ${ARGN}) | ||
| 519 | + endif() | ||
| 520 | + | ||
| 521 | +endfunction() | ||
| 522 | + | ||
| 523 | + | ||
| 524 | +# Internal use, projects must not call this directly. It is | ||
| 525 | +# intended for use by the FetchContent_Declare() function. | ||
| 526 | +# | ||
| 527 | +# Retrieves details saved for the specified content in an | ||
| 528 | +# earlier call to __FetchContent_declareDetails(). | ||
| 529 | +function(__FetchContent_getSavedDetails contentName outVar) | ||
| 530 | + | ||
| 531 | + string(TOLOWER ${contentName} contentNameLower) | ||
| 532 | + set(propertyName "_FetchContent_${contentNameLower}_savedDetails") | ||
| 533 | + get_property(alreadyDefined GLOBAL PROPERTY ${propertyName} DEFINED) | ||
| 534 | + if(NOT alreadyDefined) | ||
| 535 | + message(FATAL_ERROR "No content details recorded for ${contentName}") | ||
| 536 | + endif() | ||
| 537 | + get_property(propertyValue GLOBAL PROPERTY ${propertyName}) | ||
| 538 | + set(${outVar} "${propertyValue}" PARENT_SCOPE) | ||
| 539 | + | ||
| 540 | +endfunction() | ||
| 541 | + | ||
| 542 | + | ||
| 543 | +# Saves population details of the content, sets defaults for the | ||
| 544 | +# SOURCE_DIR and BUILD_DIR. | ||
| 545 | +function(FetchContent_Declare contentName) | ||
| 546 | + | ||
| 547 | + set(options "") | ||
| 548 | + set(oneValueArgs SVN_REPOSITORY) | ||
| 549 | + set(multiValueArgs "") | ||
| 550 | + | ||
| 551 | + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) | ||
| 552 | + | ||
| 553 | + unset(srcDirSuffix) | ||
| 554 | + unset(svnRepoArgs) | ||
| 555 | + if(ARG_SVN_REPOSITORY) | ||
| 556 | + # Add a hash of the svn repository URL to the source dir. This works | ||
| 557 | + # around the problem where if the URL changes, the download would | ||
| 558 | + # fail because it tries to checkout/update rather than switch the | ||
| 559 | + # old URL to the new one. We limit the hash to the first 7 characters | ||
| 560 | + # so that the source path doesn't get overly long (which can be a | ||
| 561 | + # problem on windows due to path length limits). | ||
| 562 | + string(SHA1 urlSHA ${ARG_SVN_REPOSITORY}) | ||
| 563 | + string(SUBSTRING ${urlSHA} 0 7 urlSHA) | ||
| 564 | + set(srcDirSuffix "-${urlSHA}") | ||
| 565 | + set(svnRepoArgs SVN_REPOSITORY ${ARG_SVN_REPOSITORY}) | ||
| 566 | + endif() | ||
| 567 | + | ||
| 568 | + string(TOLOWER ${contentName} contentNameLower) | ||
| 569 | + __FetchContent_declareDetails( | ||
| 570 | + ${contentNameLower} | ||
| 571 | + SOURCE_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-src${srcDirSuffix}" | ||
| 572 | + BINARY_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-build" | ||
| 573 | + ${svnRepoArgs} | ||
| 574 | + # List these last so they can override things we set above | ||
| 575 | + ${ARG_UNPARSED_ARGUMENTS} | ||
| 576 | + ) | ||
| 577 | + | ||
| 578 | +endfunction() | ||
| 579 | + | ||
| 580 | + | ||
| 581 | +#======================================================================= | ||
| 582 | +# Set/get whether the specified content has been populated yet. | ||
| 583 | +# The setter also records the source and binary dirs used. | ||
| 584 | +#======================================================================= | ||
| 585 | + | ||
| 586 | +# Internal use, projects must not call this directly. It is | ||
| 587 | +# intended for use by the FetchContent_Populate() function to | ||
| 588 | +# record when FetchContent_Populate() is called for a particular | ||
| 589 | +# content name. | ||
| 590 | +function(__FetchContent_setPopulated contentName sourceDir binaryDir) | ||
| 591 | + | ||
| 592 | + string(TOLOWER ${contentName} contentNameLower) | ||
| 593 | + set(prefix "_FetchContent_${contentNameLower}") | ||
| 594 | + | ||
| 595 | + set(propertyName "${prefix}_sourceDir") | ||
| 596 | + define_property(GLOBAL PROPERTY ${propertyName} | ||
| 597 | + BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()" | ||
| 598 | + FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}" | ||
| 599 | + ) | ||
| 600 | + set_property(GLOBAL PROPERTY ${propertyName} ${sourceDir}) | ||
| 601 | + | ||
| 602 | + set(propertyName "${prefix}_binaryDir") | ||
| 603 | + define_property(GLOBAL PROPERTY ${propertyName} | ||
| 604 | + BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()" | ||
| 605 | + FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}" | ||
| 606 | + ) | ||
| 607 | + set_property(GLOBAL PROPERTY ${propertyName} ${binaryDir}) | ||
| 608 | + | ||
| 609 | + set(propertyName "${prefix}_populated") | ||
| 610 | + define_property(GLOBAL PROPERTY ${propertyName} | ||
| 611 | + BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()" | ||
| 612 | + FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}" | ||
| 613 | + ) | ||
| 614 | + set_property(GLOBAL PROPERTY ${propertyName} True) | ||
| 615 | + | ||
| 616 | +endfunction() | ||
| 617 | + | ||
| 618 | + | ||
| 619 | +# Set variables in the calling scope for any of the retrievable | ||
| 620 | +# properties. If no specific properties are requested, variables | ||
| 621 | +# will be set for all retrievable properties. | ||
| 622 | +# | ||
| 623 | +# This function is intended to also be used by projects as the canonical | ||
| 624 | +# way to detect whether they should call FetchContent_Populate() | ||
| 625 | +# and pull the populated source into the build with add_subdirectory(), | ||
| 626 | +# if they are using the populated content in that way. | ||
| 627 | +function(FetchContent_GetProperties contentName) | ||
| 628 | + | ||
| 629 | + string(TOLOWER ${contentName} contentNameLower) | ||
| 630 | + | ||
| 631 | + set(options "") | ||
| 632 | + set(oneValueArgs SOURCE_DIR BINARY_DIR POPULATED) | ||
| 633 | + set(multiValueArgs "") | ||
| 634 | + | ||
| 635 | + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) | ||
| 636 | + | ||
| 637 | + if(NOT ARG_SOURCE_DIR AND | ||
| 638 | + NOT ARG_BINARY_DIR AND | ||
| 639 | + NOT ARG_POPULATED) | ||
| 640 | + # No specific properties requested, provide them all | ||
| 641 | + set(ARG_SOURCE_DIR ${contentNameLower}_SOURCE_DIR) | ||
| 642 | + set(ARG_BINARY_DIR ${contentNameLower}_BINARY_DIR) | ||
| 643 | + set(ARG_POPULATED ${contentNameLower}_POPULATED) | ||
| 644 | + endif() | ||
| 645 | + | ||
| 646 | + set(prefix "_FetchContent_${contentNameLower}") | ||
| 647 | + | ||
| 648 | + if(ARG_SOURCE_DIR) | ||
| 649 | + set(propertyName "${prefix}_sourceDir") | ||
| 650 | + get_property(value GLOBAL PROPERTY ${propertyName}) | ||
| 651 | + if(value) | ||
| 652 | + set(${ARG_SOURCE_DIR} ${value} PARENT_SCOPE) | ||
| 653 | + endif() | ||
| 654 | + endif() | ||
| 655 | + | ||
| 656 | + if(ARG_BINARY_DIR) | ||
| 657 | + set(propertyName "${prefix}_binaryDir") | ||
| 658 | + get_property(value GLOBAL PROPERTY ${propertyName}) | ||
| 659 | + if(value) | ||
| 660 | + set(${ARG_BINARY_DIR} ${value} PARENT_SCOPE) | ||
| 661 | + endif() | ||
| 662 | + endif() | ||
| 663 | + | ||
| 664 | + if(ARG_POPULATED) | ||
| 665 | + set(propertyName "${prefix}_populated") | ||
| 666 | + get_property(value GLOBAL PROPERTY ${propertyName} DEFINED) | ||
| 667 | + set(${ARG_POPULATED} ${value} PARENT_SCOPE) | ||
| 668 | + endif() | ||
| 669 | + | ||
| 670 | +endfunction() | ||
| 671 | + | ||
| 672 | + | ||
| 673 | +#======================================================================= | ||
| 674 | +# Performing the population | ||
| 675 | +#======================================================================= | ||
| 676 | + | ||
| 677 | +# The value of contentName will always have been lowercased by the caller. | ||
| 678 | +# All other arguments are assumed to be options that are understood by | ||
| 679 | +# ExternalProject_Add(), except for QUIET and SUBBUILD_DIR. | ||
| 680 | +function(__FetchContent_directPopulate contentName) | ||
| 681 | + | ||
| 682 | + set(options | ||
| 683 | + QUIET | ||
| 684 | + ) | ||
| 685 | + set(oneValueArgs | ||
| 686 | + SUBBUILD_DIR | ||
| 687 | + SOURCE_DIR | ||
| 688 | + BINARY_DIR | ||
| 689 | + # Prevent the following from being passed through | ||
| 690 | + CONFIGURE_COMMAND | ||
| 691 | + BUILD_COMMAND | ||
| 692 | + INSTALL_COMMAND | ||
| 693 | + TEST_COMMAND | ||
| 694 | + ) | ||
| 695 | + set(multiValueArgs "") | ||
| 696 | + | ||
| 697 | + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) | ||
| 698 | + | ||
| 699 | + if(NOT ARG_SUBBUILD_DIR) | ||
| 700 | + message(FATAL_ERROR "Internal error: SUBBUILD_DIR not set") | ||
| 701 | + elseif(NOT IS_ABSOLUTE "${ARG_SUBBUILD_DIR}") | ||
| 702 | + set(ARG_SUBBUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/${ARG_SUBBUILD_DIR}") | ||
| 703 | + endif() | ||
| 704 | + | ||
| 705 | + if(NOT ARG_SOURCE_DIR) | ||
| 706 | + message(FATAL_ERROR "Internal error: SOURCE_DIR not set") | ||
| 707 | + elseif(NOT IS_ABSOLUTE "${ARG_SOURCE_DIR}") | ||
| 708 | + set(ARG_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/${ARG_SOURCE_DIR}") | ||
| 709 | + endif() | ||
| 710 | + | ||
| 711 | + if(NOT ARG_BINARY_DIR) | ||
| 712 | + message(FATAL_ERROR "Internal error: BINARY_DIR not set") | ||
| 713 | + elseif(NOT IS_ABSOLUTE "${ARG_BINARY_DIR}") | ||
| 714 | + set(ARG_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/${ARG_BINARY_DIR}") | ||
| 715 | + endif() | ||
| 716 | + | ||
| 717 | + # Ensure the caller can know where to find the source and build directories | ||
| 718 | + # with some convenient variables. Doing this here ensures the caller sees | ||
| 719 | + # the correct result in the case where the default values are overridden by | ||
| 720 | + # the content details set by the project. | ||
| 721 | + set(${contentName}_SOURCE_DIR "${ARG_SOURCE_DIR}" PARENT_SCOPE) | ||
| 722 | + set(${contentName}_BINARY_DIR "${ARG_BINARY_DIR}" PARENT_SCOPE) | ||
| 723 | + | ||
| 724 | + # The unparsed arguments may contain spaces, so build up ARG_EXTRA | ||
| 725 | + # in such a way that it correctly substitutes into the generated | ||
| 726 | + # CMakeLists.txt file with each argument quoted. | ||
| 727 | + unset(ARG_EXTRA) | ||
| 728 | + foreach(arg IN LISTS ARG_UNPARSED_ARGUMENTS) | ||
| 729 | + set(ARG_EXTRA "${ARG_EXTRA} \"${arg}\"") | ||
| 730 | + endforeach() | ||
| 731 | + | ||
| 732 | + # Hide output if requested, but save it to a variable in case there's an | ||
| 733 | + # error so we can show the output upon failure. When not quiet, don't | ||
| 734 | + # capture the output to a variable because the user may want to see the | ||
| 735 | + # output as it happens (e.g. progress during long downloads). Combine both | ||
| 736 | + # stdout and stderr in the one capture variable so the output stays in order. | ||
| 737 | + if (ARG_QUIET) | ||
| 738 | + set(outputOptions | ||
| 739 | + OUTPUT_VARIABLE capturedOutput | ||
| 740 | + ERROR_VARIABLE capturedOutput | ||
| 741 | + ) | ||
| 742 | + else() | ||
| 743 | + set(capturedOutput) | ||
| 744 | + set(outputOptions) | ||
| 745 | + message(STATUS "Populating ${contentName}") | ||
| 746 | + endif() | ||
| 747 | + | ||
| 748 | + if(CMAKE_GENERATOR) | ||
| 749 | + set(generatorOpts "-G${CMAKE_GENERATOR}") | ||
| 750 | + if(CMAKE_GENERATOR_PLATFORM) | ||
| 751 | + list(APPEND generatorOpts "-A${CMAKE_GENERATOR_PLATFORM}") | ||
| 752 | + endif() | ||
| 753 | + if(CMAKE_GENERATOR_TOOLSET) | ||
| 754 | + list(APPEND generatorOpts "-T${CMAKE_GENERATOR_TOOLSET}") | ||
| 755 | + endif() | ||
| 756 | + | ||
| 757 | + if(CMAKE_MAKE_PROGRAM) | ||
| 758 | + list(APPEND generatorOpts "-DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}") | ||
| 759 | + endif() | ||
| 760 | + | ||
| 761 | + else() | ||
| 762 | + # Likely we've been invoked via CMake's script mode where no | ||
| 763 | + # generator is set (and hence CMAKE_MAKE_PROGRAM could not be | ||
| 764 | + # trusted even if provided). We will have to rely on being | ||
| 765 | + # able to find the default generator and build tool. | ||
| 766 | + unset(generatorOpts) | ||
| 767 | + endif() | ||
| 768 | + | ||
| 769 | + # Create and build a separate CMake project to carry out the population. | ||
| 770 | + # If we've already previously done these steps, they will not cause | ||
| 771 | + # anything to be updated, so extra rebuilds of the project won't occur. | ||
| 772 | + # Make sure to pass through CMAKE_MAKE_PROGRAM in case the main project | ||
| 773 | + # has this set to something not findable on the PATH. | ||
| 774 | + configure_file("${__FetchContent_privateDir}/CMakeLists.cmake.in" | ||
| 775 | + "${ARG_SUBBUILD_DIR}/CMakeLists.txt") | ||
| 776 | + execute_process( | ||
| 777 | + COMMAND ${CMAKE_COMMAND} ${generatorOpts} . | ||
| 778 | + RESULT_VARIABLE result | ||
| 779 | + ${outputOptions} | ||
| 780 | + WORKING_DIRECTORY "${ARG_SUBBUILD_DIR}" | ||
| 781 | + ) | ||
| 782 | + if(result) | ||
| 783 | + if(capturedOutput) | ||
| 784 | + message("${capturedOutput}") | ||
| 785 | + endif() | ||
| 786 | + message(FATAL_ERROR "CMake step for ${contentName} failed: ${result}") | ||
| 787 | + endif() | ||
| 788 | + execute_process( | ||
| 789 | + COMMAND ${CMAKE_COMMAND} --build . | ||
| 790 | + RESULT_VARIABLE result | ||
| 791 | + ${outputOptions} | ||
| 792 | + WORKING_DIRECTORY "${ARG_SUBBUILD_DIR}" | ||
| 793 | + ) | ||
| 794 | + if(result) | ||
| 795 | + if(capturedOutput) | ||
| 796 | + message("${capturedOutput}") | ||
| 797 | + endif() | ||
| 798 | + message(FATAL_ERROR "Build step for ${contentName} failed: ${result}") | ||
| 799 | + endif() | ||
| 800 | + | ||
| 801 | +endfunction() | ||
| 802 | + | ||
| 803 | + | ||
| 804 | +option(FETCHCONTENT_FULLY_DISCONNECTED "Disables all attempts to download or update content and assumes source dirs already exist") | ||
| 805 | +option(FETCHCONTENT_UPDATES_DISCONNECTED "Enables UPDATE_DISCONNECTED behavior for all content population") | ||
| 806 | +option(FETCHCONTENT_QUIET "Enables QUIET option for all content population" ON) | ||
| 807 | +set(FETCHCONTENT_BASE_DIR "${CMAKE_BINARY_DIR}/_deps" CACHE PATH "Directory under which to collect all populated content") | ||
| 808 | + | ||
| 809 | +# Populate the specified content using details stored from | ||
| 810 | +# an earlier call to FetchContent_Declare(). | ||
| 811 | +function(FetchContent_Populate contentName) | ||
| 812 | + | ||
| 813 | + if(NOT contentName) | ||
| 814 | + message(FATAL_ERROR "Empty contentName not allowed for FetchContent_Populate()") | ||
| 815 | + endif() | ||
| 816 | + | ||
| 817 | + string(TOLOWER ${contentName} contentNameLower) | ||
| 818 | + | ||
| 819 | + if(ARGN) | ||
| 820 | + # This is the direct population form with details fully specified | ||
| 821 | + # as part of the call, so we already have everything we need | ||
| 822 | + __FetchContent_directPopulate( | ||
| 823 | + ${contentNameLower} | ||
| 824 | + SUBBUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/${contentNameLower}-subbuild" | ||
| 825 | + SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/${contentNameLower}-src" | ||
| 826 | + BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/${contentNameLower}-build" | ||
| 827 | + ${ARGN} # Could override any of the above ..._DIR variables | ||
| 828 | + ) | ||
| 829 | + | ||
| 830 | + # Pass source and binary dir variables back to the caller | ||
| 831 | + set(${contentNameLower}_SOURCE_DIR "${${contentNameLower}_SOURCE_DIR}" PARENT_SCOPE) | ||
| 832 | + set(${contentNameLower}_BINARY_DIR "${${contentNameLower}_BINARY_DIR}" PARENT_SCOPE) | ||
| 833 | + | ||
| 834 | + # Don't set global properties, or record that we did this population, since | ||
| 835 | + # this was a direct call outside of the normal declared details form. | ||
| 836 | + # We only want to save values in the global properties for content that | ||
| 837 | + # honours the hierarchical details mechanism so that projects are not | ||
| 838 | + # robbed of the ability to override details set in nested projects. | ||
| 839 | + return() | ||
| 840 | + endif() | ||
| 841 | + | ||
| 842 | + # No details provided, so assume they were saved from an earlier call | ||
| 843 | + # to FetchContent_Declare(). Do a check that we haven't already | ||
| 844 | + # populated this content before in case the caller forgot to check. | ||
| 845 | + FetchContent_GetProperties(${contentName}) | ||
| 846 | + if(${contentNameLower}_POPULATED) | ||
| 847 | + message(FATAL_ERROR "Content ${contentName} already populated in ${${contentNameLower}_SOURCE_DIR}") | ||
| 848 | + endif() | ||
| 849 | + | ||
| 850 | + string(TOUPPER ${contentName} contentNameUpper) | ||
| 851 | + set(FETCHCONTENT_SOURCE_DIR_${contentNameUpper} | ||
| 852 | + "${FETCHCONTENT_SOURCE_DIR_${contentNameUpper}}" | ||
| 853 | + CACHE PATH "When not empty, overrides where to find pre-populated content for ${contentName}") | ||
| 854 | + | ||
| 855 | + if(FETCHCONTENT_SOURCE_DIR_${contentNameUpper}) | ||
| 856 | + # The source directory has been explicitly provided in the cache, | ||
| 857 | + # so no population is required | ||
| 858 | + set(${contentNameLower}_SOURCE_DIR "${FETCHCONTENT_SOURCE_DIR_${contentNameUpper}}") | ||
| 859 | + set(${contentNameLower}_BINARY_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-build") | ||
| 860 | + | ||
| 861 | + elseif(FETCHCONTENT_FULLY_DISCONNECTED) | ||
| 862 | + # Bypass population and assume source is already there from a previous run | ||
| 863 | + set(${contentNameLower}_SOURCE_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-src") | ||
| 864 | + set(${contentNameLower}_BINARY_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-build") | ||
| 865 | + | ||
| 866 | + else() | ||
| 867 | + # Support both a global "disconnect all updates" and a per-content | ||
| 868 | + # update test (either one being set disables updates for this content). | ||
| 869 | + option(FETCHCONTENT_UPDATES_DISCONNECTED_${contentNameUpper} | ||
| 870 | + "Enables UPDATE_DISCONNECTED behavior just for population of ${contentName}") | ||
| 871 | + if(FETCHCONTENT_UPDATES_DISCONNECTED OR | ||
| 872 | + FETCHCONTENT_UPDATES_DISCONNECTED_${contentNameUpper}) | ||
| 873 | + set(disconnectUpdates True) | ||
| 874 | + else() | ||
| 875 | + set(disconnectUpdates False) | ||
| 876 | + endif() | ||
| 877 | + | ||
| 878 | + if(FETCHCONTENT_QUIET) | ||
| 879 | + set(quietFlag QUIET) | ||
| 880 | + else() | ||
| 881 | + unset(quietFlag) | ||
| 882 | + endif() | ||
| 883 | + | ||
| 884 | + __FetchContent_getSavedDetails(${contentName} contentDetails) | ||
| 885 | + if("${contentDetails}" STREQUAL "") | ||
| 886 | + message(FATAL_ERROR "No details have been set for content: ${contentName}") | ||
| 887 | + endif() | ||
| 888 | + | ||
| 889 | + __FetchContent_directPopulate( | ||
| 890 | + ${contentNameLower} | ||
| 891 | + ${quietFlag} | ||
| 892 | + UPDATE_DISCONNECTED ${disconnectUpdates} | ||
| 893 | + SUBBUILD_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-subbuild" | ||
| 894 | + SOURCE_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-src" | ||
| 895 | + BINARY_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-build" | ||
| 896 | + # Put the saved details last so they can override any of the | ||
| 897 | + # the options we set above (this can include SOURCE_DIR or | ||
| 898 | + # BUILD_DIR) | ||
| 899 | + ${contentDetails} | ||
| 900 | + ) | ||
| 901 | + endif() | ||
| 902 | + | ||
| 903 | + __FetchContent_setPopulated( | ||
| 904 | + ${contentName} | ||
| 905 | + ${${contentNameLower}_SOURCE_DIR} | ||
| 906 | + ${${contentNameLower}_BINARY_DIR} | ||
| 907 | + ) | ||
| 908 | + | ||
| 909 | + # Pass variables back to the caller. The variables passed back here | ||
| 910 | + # must match what FetchContent_GetProperties() sets when it is called | ||
| 911 | + # with just the content name. | ||
| 912 | + set(${contentNameLower}_SOURCE_DIR "${${contentNameLower}_SOURCE_DIR}" PARENT_SCOPE) | ||
| 913 | + set(${contentNameLower}_BINARY_DIR "${${contentNameLower}_BINARY_DIR}" PARENT_SCOPE) | ||
| 914 | + set(${contentNameLower}_POPULATED True PARENT_SCOPE) | ||
| 915 | + | ||
| 916 | +endfunction() |
| 1 | +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying | ||
| 2 | +# file Copyright.txt or https://cmake.org/licensing for details. | ||
| 3 | + | ||
| 4 | +cmake_minimum_required(VERSION ${CMAKE_VERSION}) | ||
| 5 | + | ||
| 6 | +# We name the project and the target for the ExternalProject_Add() call | ||
| 7 | +# to something that will highlight to the user what we are working on if | ||
| 8 | +# something goes wrong and an error message is produced. | ||
| 9 | + | ||
| 10 | +project(${contentName}-populate NONE) | ||
| 11 | + | ||
| 12 | +include(ExternalProject) | ||
| 13 | +ExternalProject_Add(${contentName}-populate | ||
| 14 | + ${ARG_EXTRA} | ||
| 15 | + SOURCE_DIR "${ARG_SOURCE_DIR}" | ||
| 16 | + BINARY_DIR "${ARG_BINARY_DIR}" | ||
| 17 | + CONFIGURE_COMMAND "" | ||
| 18 | + BUILD_COMMAND "" | ||
| 19 | + INSTALL_COMMAND "" | ||
| 20 | + TEST_COMMAND "" | ||
| 21 | +) |
cmake/Modules/README.md
0 → 100644
cmake/googletest.cmake
0 → 100644
| 1 | +# Copyright 2020 Fangjun Kuang (csukuangfj@gmail.com) | ||
| 2 | +# See ../LICENSE for clarification regarding multiple authors | ||
| 3 | +# | ||
| 4 | +# Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | +# you may not use this file except in compliance with the License. | ||
| 6 | +# You may obtain a copy of the License at | ||
| 7 | +# | ||
| 8 | +# http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | +# | ||
| 10 | +# Unless required by applicable law or agreed to in writing, software | ||
| 11 | +# distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | +# See the License for the specific language governing permissions and | ||
| 14 | +# limitations under the License. | ||
| 15 | + | ||
| 16 | +function(download_googltest) | ||
| 17 | + if(CMAKE_VERSION VERSION_LESS 3.11) | ||
| 18 | + # FetchContent is available since 3.11, | ||
| 19 | + # we've copied it to ${CMAKE_SOURCE_DIR}/cmake/Modules | ||
| 20 | + # so that it can be used in lower CMake versions. | ||
| 21 | + message(STATUS "Use FetchContent provided by sherpa-onnx") | ||
| 22 | + list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules) | ||
| 23 | + endif() | ||
| 24 | + | ||
| 25 | + include(FetchContent) | ||
| 26 | + | ||
| 27 | + set(googletest_URL "https://github.com/google/googletest/archive/release-1.10.0.tar.gz") | ||
| 28 | + set(googletest_HASH "SHA256=9dc9157a9a1551ec7a7e43daea9a694a0bb5fb8bec81235d8a1e6ef64c716dcb") | ||
| 29 | + | ||
| 30 | + set(BUILD_GMOCK ON CACHE BOOL "" FORCE) | ||
| 31 | + set(INSTALL_GTEST OFF CACHE BOOL "" FORCE) | ||
| 32 | + set(gtest_disable_pthreads ON CACHE BOOL "" FORCE) | ||
| 33 | + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) | ||
| 34 | + | ||
| 35 | + FetchContent_Declare(googletest | ||
| 36 | + URL ${googletest_URL} | ||
| 37 | + URL_HASH ${googletest_HASH} | ||
| 38 | + ) | ||
| 39 | + | ||
| 40 | + FetchContent_GetProperties(googletest) | ||
| 41 | + if(NOT googletest_POPULATED) | ||
| 42 | + message(STATUS "Downloading googletest") | ||
| 43 | + FetchContent_Populate(googletest) | ||
| 44 | + endif() | ||
| 45 | + message(STATUS "googletest is downloaded to ${googletest_SOURCE_DIR}") | ||
| 46 | + message(STATUS "googletest's binary dir is ${googletest_BINARY_DIR}") | ||
| 47 | + | ||
| 48 | + if(APPLE) | ||
| 49 | + set(CMAKE_MACOSX_RPATH ON) # to solve the following warning on macOS | ||
| 50 | + endif() | ||
| 51 | + #[==[ | ||
| 52 | + -- Generating done | ||
| 53 | + Policy CMP0042 is not set: MACOSX_RPATH is enabled by default. Run "cmake | ||
| 54 | + --help-policy CMP0042" for policy details. Use the cmake_policy command to | ||
| 55 | + set the policy and suppress this warning. | ||
| 56 | + | ||
| 57 | + MACOSX_RPATH is not specified for the following targets: | ||
| 58 | + | ||
| 59 | + gmock | ||
| 60 | + gmock_main | ||
| 61 | + gtest | ||
| 62 | + gtest_main | ||
| 63 | + | ||
| 64 | + This warning is for project developers. Use -Wno-dev to suppress it. | ||
| 65 | + ]==] | ||
| 66 | + | ||
| 67 | + add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR} EXCLUDE_FROM_ALL) | ||
| 68 | + | ||
| 69 | + target_include_directories(gtest | ||
| 70 | + INTERFACE | ||
| 71 | + ${googletest_SOURCE_DIR}/googletest/include | ||
| 72 | + ${googletest_SOURCE_DIR}/googlemock/include | ||
| 73 | + ) | ||
| 74 | +endfunction() | ||
| 75 | + | ||
| 76 | +download_googltest() |
cmake/kaldi-native-fbank.cmake
0 → 100644
| 1 | +function(download_kaldi_native_fbank) | ||
| 2 | + if(CMAKE_VERSION VERSION_LESS 3.11) | ||
| 3 | + # FetchContent is available since 3.11, | ||
| 4 | + # we've copied it to ${CMAKE_SOURCE_DIR}/cmake/Modules | ||
| 5 | + # so that it can be used in lower CMake versions. | ||
| 6 | + message(STATUS "Use FetchContent provided by sherpa-onnx") | ||
| 7 | + list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules) | ||
| 8 | + endif() | ||
| 9 | + | ||
| 10 | + include(FetchContent) | ||
| 11 | + | ||
| 12 | + set(kaldi_native_fbank_URL "https://github.com/csukuangfj/kaldi-native-fbank/archive/refs/tags/v1.2.tar.gz") | ||
| 13 | + set(kaldi_native_fbank_HASH "SHA256=d4562be95b9d5e974258d3f7e8506b48e454b9b0930dcddf1db020b763418c86") | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + set(KALDI_NATIVE_FBANK_BUILD_TESTS OFF CACHE BOOL "" FORCE) | ||
| 17 | + set(KALDI_NATIVE_FBANK_BUILD_PYTHON OFF CACHE BOOL "" FORCE) | ||
| 18 | + | ||
| 19 | + FetchContent_Declare(kaldi_native_fbank | ||
| 20 | + URL ${kaldi_native_fbank_URL} | ||
| 21 | + URL_HASH ${kaldi_native_fbank_HASH} | ||
| 22 | + ) | ||
| 23 | + | ||
| 24 | + FetchContent_GetProperties(kaldi_native_fbank) | ||
| 25 | + if(NOT kaldi_native_fbank_POPULATED) | ||
| 26 | + message(STATUS "Downloading kaldi-native-fbank ${kaldi_native_fbank_URL}") | ||
| 27 | + FetchContent_Populate(kaldi_native_fbank) | ||
| 28 | + endif() | ||
| 29 | + message(STATUS "kaldi-native-fbank is downloaded to ${kaldi_native_fbank_SOURCE_DIR}") | ||
| 30 | + message(STATUS "kaldi-native-fbank's binary dir is ${kaldi_native_fbank_BINARY_DIR}") | ||
| 31 | + | ||
| 32 | + add_subdirectory(${kaldi_native_fbank_SOURCE_DIR} ${kaldi_native_fbank_BINARY_DIR} EXCLUDE_FROM_ALL) | ||
| 33 | + | ||
| 34 | + target_include_directories(kaldi-native-fbank-core | ||
| 35 | + INTERFACE | ||
| 36 | + ${kaldi_native_fbank_SOURCE_DIR}/ | ||
| 37 | + ) | ||
| 38 | +endfunction() | ||
| 39 | + | ||
| 40 | +download_kaldi_native_fbank() | ||
| 41 | + |
sherpa-onnx/CMakeLists.txt
0 → 100644
| 1 | +add_subdirectory(csrc) |
sherpa-onnx/csrc/CMakeLists.txt
0 → 100644
sherpa-onnx/csrc/online-fbank-test.cc
0 → 100644
| 1 | +/** | ||
| 2 | + * Copyright (c) 2022 Xiaomi Corporation (authors: Fangjun Kuang) | ||
| 3 | + * | ||
| 4 | + * See LICENSE for clarification regarding multiple authors | ||
| 5 | + * | ||
| 6 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 7 | + * you may not use this file except in compliance with the License. | ||
| 8 | + * You may obtain a copy of the License at | ||
| 9 | + * | ||
| 10 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 11 | + * | ||
| 12 | + * Unless required by applicable law or agreed to in writing, software | ||
| 13 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 14 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 15 | + * See the License for the specific language governing permissions and | ||
| 16 | + * limitations under the License. | ||
| 17 | + */ | ||
| 18 | + | ||
| 19 | +#include <iostream> | ||
| 20 | + | ||
| 21 | +#include "kaldi-native-fbank/csrc/online-feature.h" | ||
| 22 | + | ||
| 23 | +int main() { | ||
| 24 | + knf::FbankOptions opts; | ||
| 25 | + opts.frame_opts.dither = 0; | ||
| 26 | + opts.mel_opts.num_bins = 10; | ||
| 27 | + | ||
| 28 | + knf::OnlineFbank fbank(opts); | ||
| 29 | + for (int32_t i = 0; i < 1600; ++i) { | ||
| 30 | + float s = (i * i - i / 2) / 32767.; | ||
| 31 | + fbank.AcceptWaveform(16000, &s, 1); | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + std::ostringstream os; | ||
| 35 | + | ||
| 36 | + int32_t n = fbank.NumFramesReady(); | ||
| 37 | + for (int32_t i = 0; i != n; ++i) { | ||
| 38 | + const float *frame = fbank.GetFrame(i); | ||
| 39 | + for (int32_t k = 0; k != opts.mel_opts.num_bins; ++k) { | ||
| 40 | + os << frame[k] << ", "; | ||
| 41 | + } | ||
| 42 | + os << "\n"; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + std::cout << os.str() << "\n"; | ||
| 46 | + | ||
| 47 | + return 0; | ||
| 48 | +} |
-
请 注册 或 登录 后发表评论