Skip to content

Commit 0f7903e

Browse files
Reimplement REST interface using HTTP/2, HTTP3 (#371)
* Reimplement REST interface using HTTP/2 Instead of using the httplib-based HTTP server using blocking I/O in a thread per client, implement a nghttp2-based HTTP/2 server, using single-threaded non-blocking I/O directly integrated into the Broker zmq_poll() loop. * HTTP/3 server implementation Implements HTTP/3 support in the server, following the implementation in ngtcp2's server.cc example. A lot of the function logic and structure from there has been preserved for easier debugging and comparing to the example if needed. * Prepare client for HTTP/3 Use CRTP to prepare for a Http3ClientSession (not implemented yet). Signed-off-by: Frank Osterfeld <[email protected]>
1 parent e7e3a27 commit 0f7903e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+8051
-2378
lines changed

CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ else()
108108
option(OPENCMW_ENABLE_COVERAGE "Enable Coverage" OFF)
109109
endif()
110110
option(OPENCMW_ENABLE_CONCEPTS "Enable Concepts Builds" ${opencmw_MASTER_PROJECT})
111+
option(OPENCMW_DEBUG_HTTP "Enable verbose HTTP output for debugging" OFF)
112+
option(OPENCMW_PROFILE_HTTP "Enable verbose HTTP output for profiling" OFF)
111113

112114
# Very basic PCH example
113115
option(ENABLE_PCH "Enable Precompiled Headers" OFF)
@@ -124,6 +126,14 @@ if(ENABLE_PCH)
124126
<utility>)
125127
endif()
126128

129+
if(OPENCMW_DEBUG_HTTP)
130+
target_compile_definitions(opencmw_project_options INTERFACE -DOPENCMW_DEBUG_HTTP)
131+
endif()
132+
133+
if(OPENCMW_PROFILE_HTTP)
134+
target_compile_definitions(opencmw_project_options INTERFACE -DOPENCMW_PROFILE_HTTP)
135+
endif()
136+
127137
if(OPENCMW_ENABLE_TESTING)
128138
enable_testing()
129139
message("Building Tests.")

README.md

Lines changed: 70 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ where the frame-work takes care of most of the communication, [data-serialisatio
2929
and buffering, settings management, Role-Based-Access-Control (RBAC), and other boring but necessary control system integrations
3030
while still being open to expert-level modifications, extensions or improvements.
3131

32-
### General Schematic
32+
## General Schematic
3333

3434
OpenCMW combines [ZeroMQ](https://zeromq.org/)'s [Majordomo](https://rfc.zeromq.org/spec/7/) with LMAX's [disruptor](https://lmax-exchange.github.io/disruptor/)
3535
([C++ port](https://github.com/Abc-Arbitrage/Disruptor-cpp)) design pattern that both provide a very efficient lock-free mechanisms
@@ -38,7 +38,7 @@ for distributing, streaming and processing of data objects. A schematic outline
3838

3939
![OpenCMW architectural schematic](./assets/FAIR_microservice_schematic.svg)
4040

41-
### Glossary
41+
## Glossary
4242

4343
_Majordomo Broker_ or _'Broker':_ is the central authority where multiple workers can register their services, allowing clients to perform get, set or subscriptions requests.
4444
There can be multiple brokers for subset of services.
@@ -67,11 +67,11 @@ _Publisher:_ the [DataSourcePublisher](DataSourceExample.cpp) provides an interf
6767
ring-buffer with events from OpenCMW, REST services or other sources.
6868
While using disruptor ring-buffers is the preferred and most performing options, the client also supports classic patterns of registering call-back functions or returning `Future<reyly objects>` objects.
6969

70-
### OpenCMW Majordomo Protocol
70+
## OpenCMW Majordomo Protocol
7171

7272
The OpenCMW Majordomo [protocol](docs/MajordomoProtocol.md) is based on the [ZeroMQ Majordomo protocol](https://rfc.zeromq.org/spec/7/), both extending and slightly modifying it (see [the comparison](docs/Majordomo_protocol_comparison.pdf)).
7373

74-
#### Service Names
74+
### Service Names
7575

7676
Service names must always start with `/`. For consistency, this also applies to the built-in MDP broker services like `/mmi.service` (instead of `mmi.service` without leading slash as in ZeroMQ Majordomo). A service name is a non-empty alphanumerical string (also allowing `.`, `_`), that must start with `/` but not end with `/`. It contain additional `/` to denote a hierarchical structure.
7777

@@ -84,7 +84,7 @@ Examples:
8484
- `/DeviceName/Acquisition/` - invalid (trailing slash)
8585
- `/a-service/` - invalid (`-` not allowed)
8686

87-
#### Topics
87+
### Topics
8888

8989
The "topic" field (frame 5 in the [OpenCMW MDP protocol](docs/Majordomo_protocol_comparison.pdf)) specifies the topic for subscriptions and GET/SET requests. It contains a URI with the service name as path and optional query parameters to specify further requests parameters and filter criteria.
9090

@@ -99,7 +99,7 @@ Note that the whole path is considered the service name, and that there's no add
9999

100100
See also the documentation for [mdp::Topic](src/core/include/Topic.hpp).
101101

102-
#### URL to Service/Topic Mapping (mds/mdp and REST)
102+
### URL to Service/Topic Mapping (mds/mdp and REST)
103103

104104
With both the MDS/MDP-based ZeroMQ clients as well as the REST interface, a common scheme is used to map from mdp/hds/http(s) URLs used for subscriptions and requests to the OpenCMW service name and topic fields.
105105

@@ -120,7 +120,7 @@ Other examples are:
120120
- `mds://example.com:8080/DeviceName/Acquisition?signal=test` => service name `/DeviceName/Acquisition`, topic `/DeviceName/Acquisition?signal=test` (subscription via mds).
121121
- `mdp://example.com:8080/dashboards/dashboard1?what=header` => service name `/dashboards/dashboard1`, topic `/dashboards/dashboard1?what=header` (Request via mdp).
122122

123-
### Compile-Time-Reflection
123+
## Compile-Time-Reflection
124124

125125
The serialisers are based on a [compile-time-reflection](docs/CompileTimeSerialiser.md) that efficiently transform domain-objects to and from the given wire-format (binary, JSON, ...).
126126
Compile-time reflection will become part of [C++23](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0592r4.html) as described by [David Sankel et al. , “C++ Extensions for Reflection”, ISO/IEC CD TS 23619, N4856](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/n4856.pdf).
@@ -142,7 +142,7 @@ provides also an optional light-weight `constexpr` annotation template wrapper `
142142
that in turn can be used to (re-)generate and document the class definition (e.g. for other programming languages or projects that do not have the primary domain-object definition at hand)
143143
or to generate a generic [OpenAPI](https://swagger.io/specification/) definition. More details can be found [here](docs/CompileTimeSerialiser.md).
144144
145-
### Building from source
145+
## Building from source
146146
147147
Note that building from source is only required if you want to modify opencmw-cpp itself.
148148
@@ -151,7 +151,7 @@ In that case, rather take a look at the project [opencmw-cpp-example](https://gi
151151
152152
For concrete build instructions, please check the [build instructions page](docs/BuildInstructions.md).
153153
154-
### Example
154+
## Example
155155
156156
For an example on how to implement a simple, first service using opencmw-cpp, please take a look at the project [opencmw-cpp-example](https://github.com/alexxcons/opencmw-cpp-example).
157157
@@ -217,7 +217,7 @@ or RESTful (HTTP)-based high-level protocols, or through a simple RESTful web-in
217217
[comment]: <> (The basic HTML rendering is based on XXX template engine and can be customised. For more efficient, complex and cross-platform)
218218
[comment]: <> (UI designs it is planned to allow embedding of WebAssembly-based &#40;[WASM]&#40;https://en.wikipedia.org/wiki/WebAssembly&#41;&#41; applications.)
219219

220-
### Performance
220+
## Performance
221221

222222
The end-to-end transmission achieving roughly 10k messages per second for synchronous communications and
223223
about 140k messages per second for asynchronous and or publish-subscribe style data acquisition (TCP link via locahost).
@@ -241,17 +241,74 @@ Your mileage may vary depending on the specific domain-object, processing logic,
241241
but you can check and compare the results for your platform using the [RoundTripAndNotifyEvaluation](RoundTripAndNotifyEvaluation.cpp)
242242
and/or [MdpImplementationBenchmark](MdpImplementationBenchmark.cpp) benchmarks.
243243

244-
### Documentation
244+
## Testing HTTP/3
245+
246+
The openCMW REST interface supports both HTTP/2 and HTTP/3. When connecting from a browser, the browser typically first connects
247+
via HTTP/2. HTTP/2 responses contain a "alt-svc" header that informs the browser about the availability of HTTP/3. The browser
248+
then should switch to HTTP/3. Note that if HTTP/3 fails for any reason (certificates, server error etc.), the browser might remember
249+
that and not try HTTP/3 again. How to reset this depends on the browser. What I did in Google Chrome
250+
251+
1. open an private tab, open the developer console, go to "Network", enable the "Protocol" column
252+
2. connect to the service; verify in the developer console that HTTP/3 is used (Protocol should switch to`H3` after the first `H2` request)
253+
3. To reset browser status, close *all* private tabs and open a new one.
254+
255+
### SSL Certificates
256+
257+
QUIC/HTTP/3 requires the use of TLS, unencrypted servers are not possible.
258+
259+
At least in Google Chrome, the TLS stack used for QUIC seems quite separate from the normal settings, and its much stricter than for HTTP/1/2. *If
260+
anything goes wrong here, Google Chrome will silently stick with HTTP/2, or show you an error, if you're lucky*.
261+
262+
Caveats:
263+
264+
1. The certificate must be trusted inside the Chrome Certificate store (e.g. on Mac, trusting it in Keychain might silence the warning for HTTP1/2,
265+
but HTTP/3 will still fail. Add the server's public key under chrome://certificate-manager/.
266+
2. The hostname in the certificate must match what you connect via in the browser. "Works-everywhere self-signed certificates" I couldn't get to work.
267+
What I did: Create a certificate for hostname `foobar`, edit `/etc/hosts` to resolve `foobar` to the test host's IP address. Enter e.g. `https://foobar:8080`
268+
in the browser, instead of the IP address.
269+
3. For HTTP/2, you can ignore Chrome's warning with "Proceed anyway" or similar. This does not make the QUIC stack trust the certificate, HTTP/3 will
270+
not be used.
271+
4. To get the certificate's fingerprint in base64:
272+
```
273+
openssl x509 -in /path/to/demo_public.crt -noout -pubkey \
274+
| openssl pkey -pubin -outform DER \
275+
| openssl dgst -sha256 -binary \
276+
| openssl enc -base64
277+
```
278+
3. Start Chrome with these parameters to make Chrome trust the certificate
279+
```
280+
.../Google\ Chrome --enable-quic \
281+
--origin-to-force-quic-on=<yourhost>:8080 \
282+
--ignore-certificate-errors-spki-list=<base64fingerprint> \
283+
--user-data-dir=/tmp/quic-test-profile \
284+
--no-sandbox
285+
```
286+
287+
For verbose logging (netlog can be viewed in the [https://netlog-viewer.appspot.com/#import](netlog viewer)), add
288+
```
289+
--enable-logging=stderr --v=3 \
290+
--log-net-log=netlog.json --quic-version=h3
291+
```
292+
293+
### curl
294+
295+
curl needs to be built with QUIC/HTTP/3 enabled, which is not the case at least on Ubuntu 24.04. I used the docker image `badouralix/curl-http3`:
296+
297+
```
298+
docker run --rm badouralix/curl-http3 curl -k -vvvv --http3 https://<yourhost>:8080/loadTest?topic=1&intervalMs=40&payloadSize=4096&nUpdates=100&LongPollingIdx=Next"
299+
```
300+
301+
## Documentation
245302

246303
.... more to follow.
247304

248-
### Don't like Cpp?
305+
## Don't like Cpp?
249306

250307
For prototyping applications or services that do not interact with hardware-based systems, a Java-based
251308
[OpenCMW](https://github.com/fair-acc/opencmw-java) twin-project is being developed which follows the same functional style
252309
but takes advantage of more concise implementation and C++-based type safety.
253310

254-
### Acknowledgements
311+
## Acknowledgements
255312

256313
The implementation heavily relies upon and re-uses time-tried and well-established concepts from [ZeroMQ](https://zeromq.org/)
257314
(notably the [Majordomo](https://rfc.zeromq.org/spec/7/) communication pattern, see [Z-Guide](https://zguide.zeromq.org/docs/chapter4/#Service-Oriented-Reliable-Queuing-Majordomo-Pattern)

cmake/DependenciesNative.cmake

Lines changed: 108 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,118 @@
1-
# Build a static version of openssl to link into
1+
include(ExternalProject)
2+
include(GNUInstallDirs)
3+
4+
set(OPENSSL_C_FLAGS "-O3 -march=x86-64-v3" CACHE STRING "OpenSSL custom CFLAGS" FORCE)
5+
set(OPENSSL_CXX_FLAGS "-O3 -march=x86-64-v3" CACHE STRING "OpenSSL custom CXXFLAGS" FORCE)
26
set(OPENSSL_INSTALL_DIR "${CMAKE_BINARY_DIR}/openssl-install")
3-
add_library(OpenSSL::Crypto STATIC IMPORTED GLOBAL)
4-
add_library(OpenSSL::SSL STATIC IMPORTED GLOBAL)
5-
add_dependencies(OpenSSL::Crypto PUBLIC openssl-build)
6-
add_dependencies(OpenSSL::SSL PUBLIC openssl-build)
7-
set_target_properties(OpenSSL::Crypto PROPERTIES
7+
8+
# Build custom OpenSSL with QUIC support
9+
ExternalProject_Add(OpenSslProject
10+
GIT_REPOSITORY https://github.com/openssl/openssl.git
11+
GIT_TAG openssl-3.5.0 # 3.5.0 required for server-side QUIC support
12+
GIT_SHALLOW ON
13+
BUILD_BYPRODUCTS ${OPENSSL_INSTALL_DIR}/lib64/libcrypto.a ${OPENSSL_INSTALL_DIR}/lib64/libssl.a
14+
CONFIGURE_COMMAND COMMAND ./Configure CFLAGS=${OPENSSL_C_FLAGS} CXXFLAGS=${OPENSSL_CXX_FLAGS} no-shared no-tests --prefix=${OPENSSL_INSTALL_DIR} --openssldir=${OPENSSL_INSTALL_DIR} linux-x86_64
15+
UPDATE_COMMAND ""
16+
BUILD_COMMAND make -j
17+
INSTALL_COMMAND make install_sw # only installs software components (no docs, etc)
18+
BUILD_IN_SOURCE ON
19+
)
20+
21+
add_library(openssl-crypto-static STATIC IMPORTED GLOBAL)
22+
add_dependencies(openssl-crypto-static OpenSslProject)
23+
set_target_properties(openssl-crypto-static PROPERTIES
824
IMPORTED_LOCATION "${OPENSSL_INSTALL_DIR}/lib64/libcrypto.a"
925
INTERFACE_INCLUDE_DIRECTORIES "${OPENSSL_INSTALL_DIR}/include"
1026
)
11-
set_target_properties(OpenSSL::SSL PROPERTIES
27+
28+
add_library(openssl-ssl-static STATIC IMPORTED GLOBAL)
29+
add_dependencies(openssl-ssl-static OpenSslProject)
30+
set_target_properties(openssl-ssl-static PROPERTIES
1231
IMPORTED_LOCATION "${OPENSSL_INSTALL_DIR}/lib64/libssl.a"
1332
INTERFACE_INCLUDE_DIRECTORIES "${OPENSSL_INSTALL_DIR}/include"
1433
)
15-
get_target_property(libcryptoa OpenSSL::Crypto IMPORTED_LOCATION)
16-
get_target_property(libcryptoaloc OpenSSL::Crypto LOCATION)
17-
set(OPENSSL_C_FLAGS "-O3 -march=x86-64-v3" CACHE STRING "OpenSSL custom CFLAGS" FORCE)
18-
set(OPENSSL_CXX_FLAGS "-O3 -march=x86-64-v3" CACHE STRING "OpenSSL custom CXXFLAGS" FORCE)
19-
add_custom_command(
20-
OUTPUT ${OPENSSL_INSTALL_DIR}/lib64/libcrypto.a ${OPENSSL_INSTALL_DIR}/lib64/libssl.a
21-
COMMAND ${FETCHCONTENT_BASE_DIR}/openssl-source-src/Configure CFLAGS=${OPENSSL_C_FLAGS} CXXFLAGS=${OPENSSL_CXX_FLAGS} no-shared no-tests --prefix=${OPENSSL_INSTALL_DIR} --openssldir=${OPENSSL_INSTALL_DIR} linux-x86_64
22-
COMMAND make -j
23-
COMMAND make install_sw # only installs software components (no docs, etc)
24-
COMMENT "Build openssl as a static library"
25-
WORKING_DIRECTORY ${FETCHCONTENT_BASE_DIR}/openssl-source-build
34+
35+
option(ENABLE_NGHTTP_DEBUG "Enable verbose nghttp2 debug output" OFF)
36+
37+
ExternalProject_Add(Nghttp2Project
38+
GIT_REPOSITORY https://github.com/nghttp2/nghttp2
39+
GIT_TAG v1.65.0
40+
GIT_SHALLOW ON
41+
BUILD_BYPRODUCTS ${CMAKE_BINARY_DIR}/nghttp2-install/${CMAKE_INSTALL_LIBDIR}/libnghttp2.a
42+
UPDATE_COMMAND ""
43+
CMAKE_ARGS
44+
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}/nghttp2-install
45+
-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
46+
-DENABLE_LIB_ONLY:BOOL=ON
47+
-DENABLE_HTTP3:BOOL=OFF
48+
-DENABLE_DEBUG:BOOL=${ENABLE_NGHTTP_DEBUG}
49+
-DBUILD_STATIC_LIBS:BOOL=ON
50+
-BUILD_SHARED_LIBS:BOOL=OFF
51+
-DENABLE_DOC:BOOL=OFF
52+
)
53+
54+
add_library(nghttp2-static STATIC IMPORTED GLOBAL)
55+
set_target_properties(nghttp2-static PROPERTIES
56+
IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/nghttp2-install/${CMAKE_INSTALL_LIBDIR}/libnghttp2.a"
57+
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_BINARY_DIR}/nghttp2-install/include"
2658
)
27-
add_custom_target(openssl-build ALL
28-
DEPENDS ${OPENSSL_INSTALL_DIR}/lib64/libcrypto.a ${OPENSSL_INSTALL_DIR}/lib64/libssl.a
59+
add_dependencies(nghttp2-static Nghttp2Project)
60+
61+
ExternalProject_Add(Nghttp3Project
62+
GIT_REPOSITORY https://github.com/ngtcp2/nghttp3.git
63+
GIT_TAG v1.10.1
64+
GIT_SHALLOW ON
65+
BUILD_BYPRODUCTS ${CMAKE_BINARY_DIR}/nghttp3-install/${CMAKE_INSTALL_LIBDIR}/libnghttp3.a
66+
UPDATE_COMMAND ""
67+
CMAKE_ARGS
68+
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}/nghttp3-install
69+
-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
70+
-DENABLE_LIB_ONLY:BOOL=ON
71+
-DENABLE_DEBUG:BOOL=${ENABLE_NGHTTP_DEBUG}
72+
-DBUILD_STATIC_LIBS:BOOL=ON
73+
-DBUILD_SHARED_LIBS:BOOL=OFF
74+
-DENABLE_DOC:BOOL=OFF
75+
)
76+
77+
ExternalProject_Add(NgTcp2Project
78+
GIT_REPOSITORY https://github.com/ngtcp2/ngtcp2.git
79+
GIT_TAG v1.13.0
80+
GIT_SHALLOW ON
81+
PREFIX ${CMAKE_BINARY_DIR}/ngtcp2-install
82+
BUILD_BYPRODUCTS ${CMAKE_BINARY_DIR}/ngtcp2-install/${CMAKE_INSTALL_LIBDIR}/libngtcp2.a ${CMAKE_BINARY_DIR}/ngtcp2-install/${CMAKE_INSTALL_LIBDIR}/libngtcp2_crypto_ossl.a
83+
UPDATE_COMMAND ""
84+
CMAKE_ARGS
85+
-DOPENSSL_ROOT_DIR:PATH=${OPENSSL_INSTALL_DIR}
86+
-DENABLE_OPENSSL:BOOL=ON
87+
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}/ngtcp2-install
88+
-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
89+
-DENABLE_LIB_ONLY:BOOL=ON
90+
-DENABLE_DEBUG:BOOL=${ENABLE_NGHTTP_DEBUG}
91+
-DBUILD_STATIC_LIBS:BOOL=ON
92+
-DBUILD_SHARED_LIBS:BOOL=OFF
93+
DEPENDS openssl-crypto-static openssl-ssl-static
94+
)
95+
96+
add_library(ngtcp2-static STATIC IMPORTED GLOBAL)
97+
set_target_properties(ngtcp2-static PROPERTIES
98+
IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/ngtcp2-install/${CMAKE_INSTALL_LIBDIR}/libngtcp2.a"
99+
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_BINARY_DIR}/ngtcp2-install/include"
100+
)
101+
add_dependencies(ngtcp2-static NgTcp2Project)
102+
103+
add_library(ngtcp2-crypto-ossl-static STATIC IMPORTED GLOBAL)
104+
set_target_properties(ngtcp2-crypto-ossl-static PROPERTIES
105+
IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/ngtcp2-install/${CMAKE_INSTALL_LIBDIR}/libngtcp2_crypto_ossl.a"
106+
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_BINARY_DIR}/ngtcp2-install/include"
29107
)
108+
add_dependencies(ngtcp2-crypto-ossl-static NgTcp2Project)
109+
110+
add_library(nghttp3-static STATIC IMPORTED GLOBAL)
111+
set_target_properties(nghttp3-static PROPERTIES
112+
IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/nghttp3-install/${CMAKE_INSTALL_LIBDIR}/libnghttp3.a"
113+
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_BINARY_DIR}/nghttp3-install/include"
114+
)
115+
add_dependencies(nghttp3-static Nghttp3Project)
30116

31117
add_library(mustache INTERFACE)
32118
target_include_directories(mustache INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/3rd_party/kainjow)
@@ -38,6 +124,7 @@ FetchContent_Declare(
38124
GIT_TAG v4.3.5 # latest as of 2025-03-27
39125
)
40126
set(ZMQ_BUILD_TESTS OFF CACHE BOOL "Build the tests for ZeroMQ")
127+
41128
# suppress warnings for missing zeromq dependencies by disabling some features
42129
set(WITH_TLS OFF CACHE BOOL "TLS support for ZeroMQ WebSockets")
43130
set(BUILD_SHARED OFF CACHE BOOL "Build cmake shared library")
@@ -56,12 +143,6 @@ FetchContent_Declare(
56143
GIT_TAG v1.2.12 # latest v1.2.12
57144
)
58145

59-
FetchContent_Declare(
60-
openssl-source
61-
GIT_REPOSITORY https://github.com/openssl/openssl.git
62-
GIT_TAG openssl-3.4.1
63-
)
64-
65-
FetchContent_MakeAvailable(cpp-httplib zeromq openssl-source)
146+
FetchContent_MakeAvailable(cpp-httplib zeromq)
66147

67148
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/contrib) # replace contrib by extras for catch2 v3.x.x

concepts/client/CMakeLists.txt

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
if(NOT EMSCRIPTEN)
2-
add_executable(RestSubscription_example RestSubscription_example.cpp)
3-
target_link_libraries(
4-
RestSubscription_example
5-
PRIVATE core
6-
client
7-
opencmw_project_options
8-
opencmw_project_warnings
9-
assets::rest)
10-
endif()
1+
add_executable(LoadTest_client LoadTest_client.cpp)
2+
target_link_libraries(
3+
LoadTest_client
4+
PRIVATE core
5+
client
6+
opencmw_project_options
7+
opencmw_project_warnings)
118

129
add_executable(RestSubscription_client RestSubscription_client.cpp)
1310
target_link_libraries(

0 commit comments

Comments
 (0)