Skip to content

Commit

Permalink
feat core: allow embedded file in cmake/yamake
Browse files Browse the repository at this point in the history
commit_hash:b0da7c4dfc838f50b993e81a731a24c1ede5ff2c
  • Loading branch information
segoon committed Nov 30, 2024
1 parent d1356ef commit 9140947
Show file tree
Hide file tree
Showing 20 changed files with 339 additions and 1 deletion.
13 changes: 13 additions & 0 deletions .mapping.json
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@
"cmake/SetupYdbCppSDK.cmake":"taxi/uservices/userver/cmake/SetupYdbCppSDK.cmake",
"cmake/Stacktrace.cmake":"taxi/uservices/userver/cmake/Stacktrace.cmake",
"cmake/UserverCxxCompileOptionsIfSupported.cmake":"taxi/uservices/userver/cmake/UserverCxxCompileOptionsIfSupported.cmake",
"cmake/UserverEmbedFile.cmake":"taxi/uservices/userver/cmake/UserverEmbedFile.cmake",
"cmake/UserverGrpcTargets.cmake":"taxi/uservices/userver/cmake/UserverGrpcTargets.cmake",
"cmake/UserverModule.cmake":"taxi/uservices/userver/cmake/UserverModule.cmake",
"cmake/UserverPack.cmake":"taxi/uservices/userver/cmake/UserverPack.cmake",
Expand All @@ -383,6 +384,7 @@
"cmake/UserverSql.cmake":"taxi/uservices/userver/cmake/UserverSql.cmake",
"cmake/UserverTestsuite.cmake":"taxi/uservices/userver/cmake/UserverTestsuite.cmake",
"cmake/UserverVenv.cmake":"taxi/uservices/userver/cmake/UserverVenv.cmake",
"cmake/embedded_config.cmake":"taxi/uservices/userver/cmake/embedded_config.cmake",
"cmake/get_cpm.cmake":"taxi/uservices/userver/cmake/get_cpm.cmake",
"cmake/install/Config.cmake.in":"taxi/uservices/userver/cmake/install/Config.cmake.in",
"cmake/install/userver-chaotic-config.cmake":"taxi/uservices/userver/cmake/install/userver-chaotic-config.cmake",
Expand Down Expand Up @@ -3066,6 +3068,15 @@
"samples/digest_auth_service/tests/test_digest.py":"taxi/uservices/userver/samples/digest_auth_service/tests/test_digest.py",
"samples/digest_auth_service/tests/test_proxy.py":"taxi/uservices/userver/samples/digest_auth_service/tests/test_proxy.py",
"samples/digest_auth_service/user_info.hpp":"taxi/uservices/userver/samples/digest_auth_service/user_info.hpp",
"samples/embedded_files/CMakeLists.txt":"taxi/uservices/userver/samples/embedded_files/CMakeLists.txt",
"samples/embedded_files/main.cpp":"taxi/uservices/userver/samples/embedded_files/main.cpp",
"samples/embedded_files/src/hello_handler.cpp":"taxi/uservices/userver/samples/embedded_files/src/hello_handler.cpp",
"samples/embedded_files/src/hello_handler.hpp":"taxi/uservices/userver/samples/embedded_files/src/hello_handler.hpp",
"samples/embedded_files/src/say_hello.cpp":"taxi/uservices/userver/samples/embedded_files/src/say_hello.cpp",
"samples/embedded_files/src/say_hello.hpp":"taxi/uservices/userver/samples/embedded_files/src/say_hello.hpp",
"samples/embedded_files/static_config.yaml":"taxi/uservices/userver/samples/embedded_files/static_config.yaml",
"samples/embedded_files/testsuite/conftest.py":"taxi/uservices/userver/samples/embedded_files/testsuite/conftest.py",
"samples/embedded_files/testsuite/test_hello.py":"taxi/uservices/userver/samples/embedded_files/testsuite/test_hello.py",
"samples/flatbuf_service/CMakeLists.txt":"taxi/uservices/userver/samples/flatbuf_service/CMakeLists.txt",
"samples/flatbuf_service/flatbuf_service.cpp":"taxi/uservices/userver/samples/flatbuf_service/flatbuf_service.cpp",
"samples/flatbuf_service/flatbuffer_schema.fbs":"taxi/uservices/userver/samples/flatbuf_service/flatbuffer_schema.fbs",
Expand Down Expand Up @@ -4072,6 +4083,7 @@
"universal/include/userver/utils/projected_set.hpp":"taxi/uservices/userver/universal/include/userver/utils/projected_set.hpp",
"universal/include/userver/utils/rand.hpp":"taxi/uservices/userver/universal/include/userver/utils/rand.hpp",
"universal/include/userver/utils/regex.hpp":"taxi/uservices/userver/universal/include/userver/utils/regex.hpp",
"universal/include/userver/utils/resources.hpp":"taxi/uservices/userver/universal/include/userver/utils/resources.hpp",
"universal/include/userver/utils/result_store.hpp":"taxi/uservices/userver/universal/include/userver/utils/result_store.hpp",
"universal/include/userver/utils/scope_guard.hpp":"taxi/uservices/userver/universal/include/userver/utils/scope_guard.hpp",
"universal/include/userver/utils/shared_readable_ptr.hpp":"taxi/uservices/userver/universal/include/userver/utils/shared_readable_ptr.hpp",
Expand Down Expand Up @@ -4360,6 +4372,7 @@
"universal/src/utils/rand_test.cpp":"taxi/uservices/userver/universal/src/utils/rand_test.cpp",
"universal/src/utils/regex.cpp":"taxi/uservices/userver/universal/src/utils/regex.cpp",
"universal/src/utils/regex_test.cpp":"taxi/uservices/userver/universal/src/utils/regex_test.cpp",
"universal/src/utils/resources.cpp":"taxi/uservices/userver/universal/src/utils/resources.cpp",
"universal/src/utils/scope_guard_test.cpp":"taxi/uservices/userver/universal/src/utils/scope_guard_test.cpp",
"universal/src/utils/shared_readable_ptr_test.cpp":"taxi/uservices/userver/universal/src/utils/shared_readable_ptr_test.cpp",
"universal/src/utils/small_string_benchmark.cpp":"taxi/uservices/userver/universal/src/utils/small_string_benchmark.cpp",
Expand Down
38 changes: 38 additions & 0 deletions cmake/UserverEmbedFile.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
include_guard(GLOBAL)

function(userver_embed_file TARGET)
set(OPTIONS)
set(ONE_VALUE_ARGS NAME FILEPATH HPP_FILENAME)
set(MULTI_VALUE_ARGS SQL_FILES)
cmake_parse_arguments(
ARG "${OPTIONS}" "${ONE_VALUE_ARGS}" "${MULTI_VALUE_ARGS}" ${ARGN}
)
if(NOT ARG_HPP_FILENAME)
# new cmake: cmake_path(GET ARG_FILEPATH FILENAME ARG_HPP_FILENAME)
string(REGEX REPLACE ".*/" "" ARG_HPP_FILENAME "${ARG_FILEPATH}")
endif()

string(SUBSTRING "${ARG_FILEPATH}" 0 1 START)
if(NOT START STREQUAL /)
set(ARG_FILEPATH "${CMAKE_CURRENT_SOURCE_DIR}/${ARG_FILEPATH}")
endif()

set(CONFIG_HPP ${CMAKE_CURRENT_BINARY_DIR}/embedded/include/generated/${ARG_HPP_FILENAME}.hpp)
add_custom_command(
OUTPUT
${CONFIG_HPP}
DEPENDS
${USERVER_ROOT_DIR}/cmake/embedded_config.cmake
COMMAND
${CMAKE_COMMAND}
-DUSERVER_ROOT_DIR=${USERVER_ROOT_DIR}
-DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}
-DFILEPATH=${ARG_FILEPATH}
-DOUTPUT=${CONFIG_HPP}
-DNAME=${ARG_NAME}
-P ${USERVER_ROOT_DIR}/cmake/embedded_config.cmake
)
add_library(${TARGET} STATIC ${CONFIG_HPP})
target_include_directories(${TARGET} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/embedded/include)
target_link_libraries(${TARGET} PUBLIC userver::universal)
endfunction()
34 changes: 34 additions & 0 deletions cmake/embedded_config.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
cmake_policy(SET CMP0053 NEW)

set(NAMESPACE userver)
set(FILE_IN ${CMAKE_CURRENT_BINARY_DIR}/embedded.h.in)
set(TEMPLATE "
#pragma once
#include <string_view>
#include <userver/utils/resources.hpp>
__asm__(R\"(
.section .rodata
.align 16
@NAME@_begin:
.incbin \"${FILEPATH}\"
@NAME@_end:
.byte 0
@NAME@_size:
.int @NAME@_end - @NAME@_begin
.section .text
)\");
extern \"C\" const char @NAME@_begin[];
extern \"C\" const char @NAME@_end;
extern \"C\" const int @NAME@_size;
__attribute__((constructor)) void @NAME@_call() {
utils::RegisterResource(\"@NAME@\", std::string_view{@NAME@_begin, static_cast<size_t>(@NAME@_size)});
}
")
string(CONFIGURE "${TEMPLATE}" RENDERED)
file(WRITE "${OUTPUT}" "${RENDERED}")
1 change: 1 addition & 0 deletions cmake/install/userver-universal-config.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ include("${USERVER_CMAKE_DIR}/AddGoogleTests.cmake")
include("${USERVER_CMAKE_DIR}/Sanitizers.cmake")
include("${USERVER_CMAKE_DIR}/UserverSetupEnvironment.cmake")
include("${USERVER_CMAKE_DIR}/UserverVenv.cmake")
include("${USERVER_CMAKE_DIR}/UserverEmbedFile.cmake")

userver_setup_environment()
_userver_make_sanitize_blacklist()
Expand Down
7 changes: 6 additions & 1 deletion core/include/userver/utils/daemon_run.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
/// @brief Functions to start a daemon with specified components list.

#include <userver/components/component_list.hpp>
#include <userver/components/run.hpp>

USERVER_NAMESPACE_BEGIN

namespace utils {

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

/// Calls components::Run with in-memory config.
/// Reports unhandled exceptions.
int DaemonMain(const components::InMemoryConfig& config, const components::ComponentList& components_list);

} // namespace utils

USERVER_NAMESPACE_END
19 changes: 19 additions & 0 deletions core/src/utils/daemon_run.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,25 @@ int DaemonMain(const int argc, const char* const argv[], const components::Compo
}
}

int DaemonMain(const components::InMemoryConfig& config, const components::ComponentList& components_list) {
utils::impl::FinishStaticRegistration();

try {
components::Run(config, components_list);
return 0;
} catch (const std::exception& ex) {
auto msg = fmt::format("Unhandled exception in components::Run: {}", ex.what());
std::cerr << msg << "\n";
return 1;
} catch (...) {
auto msg = fmt::format(
"Non-standard exception in components::Run: {}", boost::current_exception_diagnostic_information()
);
std::cerr << msg << '\n';
return 1;
}
}

} // namespace utils

USERVER_NAMESPACE_END
3 changes: 3 additions & 0 deletions samples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}-json2yaml)
add_subdirectory(hello_service)
add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}-hello_service)

add_subdirectory(embedded_files)
add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}-embedded_files)

add_subdirectory(http_middleware_service)
add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}-http_middleware_service)

Expand Down
26 changes: 26 additions & 0 deletions samples/embedded_files/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 3.14)
project(userver-samples-embedded_files CXX)

find_package(userver COMPONENTS core REQUIRED)

add_library(${PROJECT_NAME}_objs OBJECT
src/say_hello.hpp
src/say_hello.cpp
src/hello_handler.hpp
src/hello_handler.cpp
)
target_link_libraries(${PROJECT_NAME}_objs userver::core)
target_include_directories(${PROJECT_NAME}_objs PUBLIC src)

add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} ${PROJECT_NAME}_objs)

# /// [embedded]
userver_embed_file(${PROJECT_NAME}_config
NAME static_config_yaml
FILEPATH static_config.yaml
)
target_link_libraries(${PROJECT_NAME} ${PROJECT_NAME}_config)
# /// [embedded]

userver_testsuite_add_simple()
18 changes: 18 additions & 0 deletions samples/embedded_files/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include <userver/components/minimal_server_component_list.hpp>
#include <userver/utest/using_namespace_userver.hpp>
#include <userver/utils/daemon_run.hpp>

// Note: this is for the purposes of tests/samples only
#include <userver/utest/using_namespace_userver.hpp>

#include <hello_handler.hpp>

#include <generated/static_config.yaml.hpp>

// [embedded usage]
int main(int, char*[]) {
auto component_list = components::MinimalServerComponentList().Append<samples::hello::HelloHandler>();

return utils::DaemonMain(components::InMemoryConfig{utils::FindResource("static_config_yaml")}, component_list);
}
// [embedded usage]
19 changes: 19 additions & 0 deletions samples/embedded_files/src/hello_handler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include "hello_handler.hpp"

#include "say_hello.hpp"

namespace samples::hello {

std::string HelloHandler::
HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext& /*request_context*/)
const {
// Setting Content-Type: text/plain in a microservice response ensures
// the client interprets it as plain text, preventing misinterpretation or
// errors. Without this header, the client might assume a different format,
// such as JSON, HTML or XML, leading to potential processing issues or
// incorrect handling of the data.
request.GetHttpResponse().SetContentType(http::content_type::kTextPlain);
return samples::hello::SayHelloTo(request.GetArg("name"));
}

} // namespace samples::hello
23 changes: 23 additions & 0 deletions samples/embedded_files/src/hello_handler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include <userver/components/component_list.hpp>
#include <userver/server/handlers/http_handler_base.hpp>

// Note: this is for the purposes of tests/samples only
#include <userver/utest/using_namespace_userver.hpp>

namespace samples::hello {

class HelloHandler final : public server::handlers::HttpHandlerBase {
public:
// `kName` is used as the component name in static config
static constexpr std::string_view kName = "handler-hello-sample";

// Component is valid after construction and is able to accept requests
using HttpHandlerBase::HttpHandlerBase;

std::string HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&)
const override;
};

} // namespace samples::hello
15 changes: 15 additions & 0 deletions samples/embedded_files/src/say_hello.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include "say_hello.hpp"

#include <fmt/format.h>

namespace samples::hello {

std::string SayHelloTo(std::string_view name) {
if (name.empty()) {
name = "unknown user";
}

return fmt::format("Hello, {}!\n", name);
}

} // namespace samples::hello
10 changes: 10 additions & 0 deletions samples/embedded_files/src/say_hello.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

#include <string>
#include <string_view>

namespace samples::hello {

std::string SayHelloTo(std::string_view name);

} // namespace samples::hello
28 changes: 28 additions & 0 deletions samples/embedded_files/static_config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# yaml
components_manager:
task_processors: # Task processor is an executor for coroutine tasks
main-task-processor: # Make a task processor for CPU-bound coroutine tasks.
worker_threads: 4 # Process tasks in 4 threads.

fs-task-processor: # Make a separate task processor for filesystem bound tasks.
worker_threads: 1

default_task_processor: main-task-processor # Task processor in which components start.

components: # Configuring components that were registered via component_list
server:
listener: # configuring the main listening socket...
port: 8096 # ...to listen on this port and...
task_processor: main-task-processor # ...process incoming requests on this task processor.
logging:
fs-task-processor: fs-task-processor
loggers:
default:
file_path: '@stderr'
level: debug
overflow_behavior: discard # Drop logs if the system is too busy to write them down.

handler-hello-sample: # Finally! Our handler.
path: /hello # Registering handler by URL '/hello'.
method: GET,POST # It will only reply to GET (HEAD) and POST requests.
task_processor: main-task-processor # Run it on CPU bound task processor
1 change: 1 addition & 0 deletions samples/embedded_files/testsuite/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pytest_plugins = ['pytest_userver.plugins.core']
17 changes: 17 additions & 0 deletions samples/embedded_files/testsuite/test_hello.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import pytest


# forced port is required for embedded config
@pytest.fixture(scope='session')
def service_port() -> int:
return 8096


# /// [Functional test]
async def test_hello_base(service_client):
response = await service_client.get('/hello')
assert response.status == 200
assert 'text/plain' in response.headers['Content-Type']
assert response.text == 'Hello, unknown user!\n'
assert 'X-RequestId' not in response.headers.keys(), 'Unexpected header'
# /// [Functional test]
19 changes: 19 additions & 0 deletions scripts/docs/en/userver/tutorial/hello_service.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,25 @@ and start the server with static configuration file passed from command line.

@include samples/hello_service/main.cpp

You can either pass argc, argv to `utils::DaemonRun()` to parse config yaml and config vars
filepaths from arguments, or you may use embedded config file.


### Embedded files

Sometimes it is handy to embed file(s) content into the binary to avoid additional filesystem reads.
You may use it with `userver_embed_file()` cmake function.
It generates cmake target which can be linked into your executable target.

Cmake part looks like the following:

@snippet samples/embedded_files/CMakeLists.txt embedded

C++ part looks simple - include the generated header and use `utils::FindResource()` function to
get the embedded file contents:

@snippet samples/embedded_files/main.cpp embedded usage


### CMake

Expand Down
3 changes: 3 additions & 0 deletions universal/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ _userver_directory_install(COMPONENT universal FILES
"${USERVER_ROOT_DIR}/cmake/DetectVersion.cmake"
"${USERVER_ROOT_DIR}/cmake/UserverSetupEnvironment.cmake"
"${USERVER_ROOT_DIR}/cmake/UserverVenv.cmake"
"${USERVER_ROOT_DIR}/cmake/UserverEmbedFile.cmake"
"${USERVER_ROOT_DIR}/cmake/install/userver-universal-config.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/userver
)
Expand All @@ -401,3 +402,5 @@ _userver_directory_install(COMPONENT universal FILES
"${USERVER_ROOT_DIR}/cmake/modules/FindUserverGBench.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/userver/modules
)

include(UserverEmbedFile)
Loading

0 comments on commit 9140947

Please sign in to comment.