Skip to content

Commit 9140947

Browse files
committed
feat core: allow embedded file in cmake/yamake
commit_hash:b0da7c4dfc838f50b993e81a731a24c1ede5ff2c
1 parent d1356ef commit 9140947

20 files changed

+339
-1
lines changed

.mapping.json

+13
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@
374374
"cmake/SetupYdbCppSDK.cmake":"taxi/uservices/userver/cmake/SetupYdbCppSDK.cmake",
375375
"cmake/Stacktrace.cmake":"taxi/uservices/userver/cmake/Stacktrace.cmake",
376376
"cmake/UserverCxxCompileOptionsIfSupported.cmake":"taxi/uservices/userver/cmake/UserverCxxCompileOptionsIfSupported.cmake",
377+
"cmake/UserverEmbedFile.cmake":"taxi/uservices/userver/cmake/UserverEmbedFile.cmake",
377378
"cmake/UserverGrpcTargets.cmake":"taxi/uservices/userver/cmake/UserverGrpcTargets.cmake",
378379
"cmake/UserverModule.cmake":"taxi/uservices/userver/cmake/UserverModule.cmake",
379380
"cmake/UserverPack.cmake":"taxi/uservices/userver/cmake/UserverPack.cmake",
@@ -383,6 +384,7 @@
383384
"cmake/UserverSql.cmake":"taxi/uservices/userver/cmake/UserverSql.cmake",
384385
"cmake/UserverTestsuite.cmake":"taxi/uservices/userver/cmake/UserverTestsuite.cmake",
385386
"cmake/UserverVenv.cmake":"taxi/uservices/userver/cmake/UserverVenv.cmake",
387+
"cmake/embedded_config.cmake":"taxi/uservices/userver/cmake/embedded_config.cmake",
386388
"cmake/get_cpm.cmake":"taxi/uservices/userver/cmake/get_cpm.cmake",
387389
"cmake/install/Config.cmake.in":"taxi/uservices/userver/cmake/install/Config.cmake.in",
388390
"cmake/install/userver-chaotic-config.cmake":"taxi/uservices/userver/cmake/install/userver-chaotic-config.cmake",
@@ -3066,6 +3068,15 @@
30663068
"samples/digest_auth_service/tests/test_digest.py":"taxi/uservices/userver/samples/digest_auth_service/tests/test_digest.py",
30673069
"samples/digest_auth_service/tests/test_proxy.py":"taxi/uservices/userver/samples/digest_auth_service/tests/test_proxy.py",
30683070
"samples/digest_auth_service/user_info.hpp":"taxi/uservices/userver/samples/digest_auth_service/user_info.hpp",
3071+
"samples/embedded_files/CMakeLists.txt":"taxi/uservices/userver/samples/embedded_files/CMakeLists.txt",
3072+
"samples/embedded_files/main.cpp":"taxi/uservices/userver/samples/embedded_files/main.cpp",
3073+
"samples/embedded_files/src/hello_handler.cpp":"taxi/uservices/userver/samples/embedded_files/src/hello_handler.cpp",
3074+
"samples/embedded_files/src/hello_handler.hpp":"taxi/uservices/userver/samples/embedded_files/src/hello_handler.hpp",
3075+
"samples/embedded_files/src/say_hello.cpp":"taxi/uservices/userver/samples/embedded_files/src/say_hello.cpp",
3076+
"samples/embedded_files/src/say_hello.hpp":"taxi/uservices/userver/samples/embedded_files/src/say_hello.hpp",
3077+
"samples/embedded_files/static_config.yaml":"taxi/uservices/userver/samples/embedded_files/static_config.yaml",
3078+
"samples/embedded_files/testsuite/conftest.py":"taxi/uservices/userver/samples/embedded_files/testsuite/conftest.py",
3079+
"samples/embedded_files/testsuite/test_hello.py":"taxi/uservices/userver/samples/embedded_files/testsuite/test_hello.py",
30693080
"samples/flatbuf_service/CMakeLists.txt":"taxi/uservices/userver/samples/flatbuf_service/CMakeLists.txt",
30703081
"samples/flatbuf_service/flatbuf_service.cpp":"taxi/uservices/userver/samples/flatbuf_service/flatbuf_service.cpp",
30713082
"samples/flatbuf_service/flatbuffer_schema.fbs":"taxi/uservices/userver/samples/flatbuf_service/flatbuffer_schema.fbs",
@@ -4072,6 +4083,7 @@
40724083
"universal/include/userver/utils/projected_set.hpp":"taxi/uservices/userver/universal/include/userver/utils/projected_set.hpp",
40734084
"universal/include/userver/utils/rand.hpp":"taxi/uservices/userver/universal/include/userver/utils/rand.hpp",
40744085
"universal/include/userver/utils/regex.hpp":"taxi/uservices/userver/universal/include/userver/utils/regex.hpp",
4086+
"universal/include/userver/utils/resources.hpp":"taxi/uservices/userver/universal/include/userver/utils/resources.hpp",
40754087
"universal/include/userver/utils/result_store.hpp":"taxi/uservices/userver/universal/include/userver/utils/result_store.hpp",
40764088
"universal/include/userver/utils/scope_guard.hpp":"taxi/uservices/userver/universal/include/userver/utils/scope_guard.hpp",
40774089
"universal/include/userver/utils/shared_readable_ptr.hpp":"taxi/uservices/userver/universal/include/userver/utils/shared_readable_ptr.hpp",
@@ -4360,6 +4372,7 @@
43604372
"universal/src/utils/rand_test.cpp":"taxi/uservices/userver/universal/src/utils/rand_test.cpp",
43614373
"universal/src/utils/regex.cpp":"taxi/uservices/userver/universal/src/utils/regex.cpp",
43624374
"universal/src/utils/regex_test.cpp":"taxi/uservices/userver/universal/src/utils/regex_test.cpp",
4375+
"universal/src/utils/resources.cpp":"taxi/uservices/userver/universal/src/utils/resources.cpp",
43634376
"universal/src/utils/scope_guard_test.cpp":"taxi/uservices/userver/universal/src/utils/scope_guard_test.cpp",
43644377
"universal/src/utils/shared_readable_ptr_test.cpp":"taxi/uservices/userver/universal/src/utils/shared_readable_ptr_test.cpp",
43654378
"universal/src/utils/small_string_benchmark.cpp":"taxi/uservices/userver/universal/src/utils/small_string_benchmark.cpp",

cmake/UserverEmbedFile.cmake

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
include_guard(GLOBAL)
2+
3+
function(userver_embed_file TARGET)
4+
set(OPTIONS)
5+
set(ONE_VALUE_ARGS NAME FILEPATH HPP_FILENAME)
6+
set(MULTI_VALUE_ARGS SQL_FILES)
7+
cmake_parse_arguments(
8+
ARG "${OPTIONS}" "${ONE_VALUE_ARGS}" "${MULTI_VALUE_ARGS}" ${ARGN}
9+
)
10+
if(NOT ARG_HPP_FILENAME)
11+
# new cmake: cmake_path(GET ARG_FILEPATH FILENAME ARG_HPP_FILENAME)
12+
string(REGEX REPLACE ".*/" "" ARG_HPP_FILENAME "${ARG_FILEPATH}")
13+
endif()
14+
15+
string(SUBSTRING "${ARG_FILEPATH}" 0 1 START)
16+
if(NOT START STREQUAL /)
17+
set(ARG_FILEPATH "${CMAKE_CURRENT_SOURCE_DIR}/${ARG_FILEPATH}")
18+
endif()
19+
20+
set(CONFIG_HPP ${CMAKE_CURRENT_BINARY_DIR}/embedded/include/generated/${ARG_HPP_FILENAME}.hpp)
21+
add_custom_command(
22+
OUTPUT
23+
${CONFIG_HPP}
24+
DEPENDS
25+
${USERVER_ROOT_DIR}/cmake/embedded_config.cmake
26+
COMMAND
27+
${CMAKE_COMMAND}
28+
-DUSERVER_ROOT_DIR=${USERVER_ROOT_DIR}
29+
-DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}
30+
-DFILEPATH=${ARG_FILEPATH}
31+
-DOUTPUT=${CONFIG_HPP}
32+
-DNAME=${ARG_NAME}
33+
-P ${USERVER_ROOT_DIR}/cmake/embedded_config.cmake
34+
)
35+
add_library(${TARGET} STATIC ${CONFIG_HPP})
36+
target_include_directories(${TARGET} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/embedded/include)
37+
target_link_libraries(${TARGET} PUBLIC userver::universal)
38+
endfunction()

cmake/embedded_config.cmake

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
cmake_policy(SET CMP0053 NEW)
2+
3+
set(NAMESPACE userver)
4+
set(FILE_IN ${CMAKE_CURRENT_BINARY_DIR}/embedded.h.in)
5+
set(TEMPLATE "
6+
#pragma once
7+
8+
#include <string_view>
9+
10+
#include <userver/utils/resources.hpp>
11+
12+
__asm__(R\"(
13+
.section .rodata
14+
.align 16
15+
@NAME@_begin:
16+
.incbin \"${FILEPATH}\"
17+
@NAME@_end:
18+
.byte 0
19+
@NAME@_size:
20+
.int @NAME@_end - @NAME@_begin
21+
.section .text
22+
)\");
23+
24+
extern \"C\" const char @NAME@_begin[];
25+
extern \"C\" const char @NAME@_end;
26+
extern \"C\" const int @NAME@_size;
27+
28+
29+
__attribute__((constructor)) void @NAME@_call() {
30+
utils::RegisterResource(\"@NAME@\", std::string_view{@NAME@_begin, static_cast<size_t>(@NAME@_size)});
31+
}
32+
")
33+
string(CONFIGURE "${TEMPLATE}" RENDERED)
34+
file(WRITE "${OUTPUT}" "${RENDERED}")

cmake/install/userver-universal-config.cmake

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ include("${USERVER_CMAKE_DIR}/AddGoogleTests.cmake")
3939
include("${USERVER_CMAKE_DIR}/Sanitizers.cmake")
4040
include("${USERVER_CMAKE_DIR}/UserverSetupEnvironment.cmake")
4141
include("${USERVER_CMAKE_DIR}/UserverVenv.cmake")
42+
include("${USERVER_CMAKE_DIR}/UserverEmbedFile.cmake")
4243

4344
userver_setup_environment()
4445
_userver_make_sanitize_blacklist()

core/include/userver/utils/daemon_run.hpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44
/// @brief Functions to start a daemon with specified components list.
55

66
#include <userver/components/component_list.hpp>
7+
#include <userver/components/run.hpp>
78

89
USERVER_NAMESPACE_BEGIN
910

1011
namespace utils {
1112

1213
/// Parses command line arguments and calls components::Run with config file
13-
/// from --config parameter.
14+
/// from --config parameter. Reports unhandled exceptions.
1415
///
1516
/// Other command line arguments:
1617
/// * --help - show all command line arguments
@@ -21,6 +22,10 @@ namespace utils {
2122
/// * --print-dynamic-config-defaults - print JSON with dynamic config defaults
2223
int DaemonMain(int argc, const char* const argv[], const components::ComponentList& components_list);
2324

25+
/// Calls components::Run with in-memory config.
26+
/// Reports unhandled exceptions.
27+
int DaemonMain(const components::InMemoryConfig& config, const components::ComponentList& components_list);
28+
2429
} // namespace utils
2530

2631
USERVER_NAMESPACE_END

core/src/utils/daemon_run.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,25 @@ int DaemonMain(const int argc, const char* const argv[], const components::Compo
9090
}
9191
}
9292

93+
int DaemonMain(const components::InMemoryConfig& config, const components::ComponentList& components_list) {
94+
utils::impl::FinishStaticRegistration();
95+
96+
try {
97+
components::Run(config, components_list);
98+
return 0;
99+
} catch (const std::exception& ex) {
100+
auto msg = fmt::format("Unhandled exception in components::Run: {}", ex.what());
101+
std::cerr << msg << "\n";
102+
return 1;
103+
} catch (...) {
104+
auto msg = fmt::format(
105+
"Non-standard exception in components::Run: {}", boost::current_exception_diagnostic_information()
106+
);
107+
std::cerr << msg << '\n';
108+
return 1;
109+
}
110+
}
111+
93112
} // namespace utils
94113

95114
USERVER_NAMESPACE_END

samples/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}-json2yaml)
3838
add_subdirectory(hello_service)
3939
add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}-hello_service)
4040

41+
add_subdirectory(embedded_files)
42+
add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}-embedded_files)
43+
4144
add_subdirectory(http_middleware_service)
4245
add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}-http_middleware_service)
4346

samples/embedded_files/CMakeLists.txt

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
cmake_minimum_required(VERSION 3.14)
2+
project(userver-samples-embedded_files CXX)
3+
4+
find_package(userver COMPONENTS core REQUIRED)
5+
6+
add_library(${PROJECT_NAME}_objs OBJECT
7+
src/say_hello.hpp
8+
src/say_hello.cpp
9+
src/hello_handler.hpp
10+
src/hello_handler.cpp
11+
)
12+
target_link_libraries(${PROJECT_NAME}_objs userver::core)
13+
target_include_directories(${PROJECT_NAME}_objs PUBLIC src)
14+
15+
add_executable(${PROJECT_NAME} main.cpp)
16+
target_link_libraries(${PROJECT_NAME} ${PROJECT_NAME}_objs)
17+
18+
# /// [embedded]
19+
userver_embed_file(${PROJECT_NAME}_config
20+
NAME static_config_yaml
21+
FILEPATH static_config.yaml
22+
)
23+
target_link_libraries(${PROJECT_NAME} ${PROJECT_NAME}_config)
24+
# /// [embedded]
25+
26+
userver_testsuite_add_simple()

samples/embedded_files/main.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#include <userver/components/minimal_server_component_list.hpp>
2+
#include <userver/utest/using_namespace_userver.hpp>
3+
#include <userver/utils/daemon_run.hpp>
4+
5+
// Note: this is for the purposes of tests/samples only
6+
#include <userver/utest/using_namespace_userver.hpp>
7+
8+
#include <hello_handler.hpp>
9+
10+
#include <generated/static_config.yaml.hpp>
11+
12+
// [embedded usage]
13+
int main(int, char*[]) {
14+
auto component_list = components::MinimalServerComponentList().Append<samples::hello::HelloHandler>();
15+
16+
return utils::DaemonMain(components::InMemoryConfig{utils::FindResource("static_config_yaml")}, component_list);
17+
}
18+
// [embedded usage]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include "hello_handler.hpp"
2+
3+
#include "say_hello.hpp"
4+
5+
namespace samples::hello {
6+
7+
std::string HelloHandler::
8+
HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext& /*request_context*/)
9+
const {
10+
// Setting Content-Type: text/plain in a microservice response ensures
11+
// the client interprets it as plain text, preventing misinterpretation or
12+
// errors. Without this header, the client might assume a different format,
13+
// such as JSON, HTML or XML, leading to potential processing issues or
14+
// incorrect handling of the data.
15+
request.GetHttpResponse().SetContentType(http::content_type::kTextPlain);
16+
return samples::hello::SayHelloTo(request.GetArg("name"));
17+
}
18+
19+
} // namespace samples::hello
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#pragma once
2+
3+
#include <userver/components/component_list.hpp>
4+
#include <userver/server/handlers/http_handler_base.hpp>
5+
6+
// Note: this is for the purposes of tests/samples only
7+
#include <userver/utest/using_namespace_userver.hpp>
8+
9+
namespace samples::hello {
10+
11+
class HelloHandler final : public server::handlers::HttpHandlerBase {
12+
public:
13+
// `kName` is used as the component name in static config
14+
static constexpr std::string_view kName = "handler-hello-sample";
15+
16+
// Component is valid after construction and is able to accept requests
17+
using HttpHandlerBase::HttpHandlerBase;
18+
19+
std::string HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&)
20+
const override;
21+
};
22+
23+
} // namespace samples::hello
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include "say_hello.hpp"
2+
3+
#include <fmt/format.h>
4+
5+
namespace samples::hello {
6+
7+
std::string SayHelloTo(std::string_view name) {
8+
if (name.empty()) {
9+
name = "unknown user";
10+
}
11+
12+
return fmt::format("Hello, {}!\n", name);
13+
}
14+
15+
} // namespace samples::hello
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include <string_view>
5+
6+
namespace samples::hello {
7+
8+
std::string SayHelloTo(std::string_view name);
9+
10+
} // namespace samples::hello
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# yaml
2+
components_manager:
3+
task_processors: # Task processor is an executor for coroutine tasks
4+
main-task-processor: # Make a task processor for CPU-bound coroutine tasks.
5+
worker_threads: 4 # Process tasks in 4 threads.
6+
7+
fs-task-processor: # Make a separate task processor for filesystem bound tasks.
8+
worker_threads: 1
9+
10+
default_task_processor: main-task-processor # Task processor in which components start.
11+
12+
components: # Configuring components that were registered via component_list
13+
server:
14+
listener: # configuring the main listening socket...
15+
port: 8096 # ...to listen on this port and...
16+
task_processor: main-task-processor # ...process incoming requests on this task processor.
17+
logging:
18+
fs-task-processor: fs-task-processor
19+
loggers:
20+
default:
21+
file_path: '@stderr'
22+
level: debug
23+
overflow_behavior: discard # Drop logs if the system is too busy to write them down.
24+
25+
handler-hello-sample: # Finally! Our handler.
26+
path: /hello # Registering handler by URL '/hello'.
27+
method: GET,POST # It will only reply to GET (HEAD) and POST requests.
28+
task_processor: main-task-processor # Run it on CPU bound task processor
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pytest_plugins = ['pytest_userver.plugins.core']
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import pytest
2+
3+
4+
# forced port is required for embedded config
5+
@pytest.fixture(scope='session')
6+
def service_port() -> int:
7+
return 8096
8+
9+
10+
# /// [Functional test]
11+
async def test_hello_base(service_client):
12+
response = await service_client.get('/hello')
13+
assert response.status == 200
14+
assert 'text/plain' in response.headers['Content-Type']
15+
assert response.text == 'Hello, unknown user!\n'
16+
assert 'X-RequestId' not in response.headers.keys(), 'Unexpected header'
17+
# /// [Functional test]

scripts/docs/en/userver/tutorial/hello_service.md

+19
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,25 @@ and start the server with static configuration file passed from command line.
8686

8787
@include samples/hello_service/main.cpp
8888

89+
You can either pass argc, argv to `utils::DaemonRun()` to parse config yaml and config vars
90+
filepaths from arguments, or you may use embedded config file.
91+
92+
93+
### Embedded files
94+
95+
Sometimes it is handy to embed file(s) content into the binary to avoid additional filesystem reads.
96+
You may use it with `userver_embed_file()` cmake function.
97+
It generates cmake target which can be linked into your executable target.
98+
99+
Cmake part looks like the following:
100+
101+
@snippet samples/embedded_files/CMakeLists.txt embedded
102+
103+
C++ part looks simple - include the generated header and use `utils::FindResource()` function to
104+
get the embedded file contents:
105+
106+
@snippet samples/embedded_files/main.cpp embedded usage
107+
89108

90109
### CMake
91110

universal/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ _userver_directory_install(COMPONENT universal FILES
389389
"${USERVER_ROOT_DIR}/cmake/DetectVersion.cmake"
390390
"${USERVER_ROOT_DIR}/cmake/UserverSetupEnvironment.cmake"
391391
"${USERVER_ROOT_DIR}/cmake/UserverVenv.cmake"
392+
"${USERVER_ROOT_DIR}/cmake/UserverEmbedFile.cmake"
392393
"${USERVER_ROOT_DIR}/cmake/install/userver-universal-config.cmake"
393394
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/userver
394395
)
@@ -401,3 +402,5 @@ _userver_directory_install(COMPONENT universal FILES
401402
"${USERVER_ROOT_DIR}/cmake/modules/FindUserverGBench.cmake"
402403
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/userver/modules
403404
)
405+
406+
include(UserverEmbedFile)

0 commit comments

Comments
 (0)