From 99eb81c0cda01bab2ec0e1cf1458e12f646730e3 Mon Sep 17 00:00:00 2001 From: Jairo Calmon Date: Thu, 4 Dec 2025 14:58:03 -0300 Subject: [PATCH 01/14] Add a nolint tag to what looks like a false positive --- BedrockServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BedrockServer.cpp b/BedrockServer.cpp index f83df6e3a..e7bd93cbc 100644 --- a/BedrockServer.cpp +++ b/BedrockServer.cpp @@ -311,7 +311,7 @@ void BedrockServer::sync() _upgradeInProgress = false; if (committingCommand) { db.rollback(); - committingCommand = false; + committingCommand = false; //NOLINT } } From f5eaf998df391fa058f37ea7012330a1860fd937 Mon Sep 17 00:00:00 2001 From: Jairo Calmon Date: Thu, 4 Dec 2025 14:59:27 -0300 Subject: [PATCH 02/14] Avoid overflow and use of strcpy (CWE-119) --- libstuff/libstuff.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/libstuff/libstuff.cpp b/libstuff/libstuff.cpp index 77db62e4d..a35333c0a 100644 --- a/libstuff/libstuff.cpp +++ b/libstuff/libstuff.cpp @@ -243,7 +243,7 @@ void SSyslogSocketDirect(int priority, const char *format, ...) { // and treats them as part of the message. string messageHeader = "<" + to_string(8 + priority) + ">" + SProcessName + ": "; thread_local char messageBuffer[MAX_MESSAGE_SIZE]; - strcpy(messageBuffer, messageHeader.c_str()); + memcpy(messageBuffer, messageHeader.c_str(), min(messageHeader.size(), (size_t) MAX_MESSAGE_SIZE)); va_list argptr; va_start(argptr, format); int bytesWritten = vsnprintf(messageBuffer + messageHeader.size(), MAX_MESSAGE_SIZE - messageHeader.size(), format, argptr); @@ -2946,15 +2946,23 @@ string SREReplace(const string& regExp, const string& input, const string& repla output = (char*)malloc(outSize); } else if (result < 0) { SHMMM("Regex replacement failed with result " << result << ", returning nothing."); + if (output) { + free(output); + } output = (char*)malloc(1); *output = 0; break; } } - string outputString(output); + + string outputString; + if (output) { + outputString = output; + free(output); + } + pcre2_code_free(re); pcre2_match_context_free(matchContext); - free(output); return outputString; } From 70e6c521573a5c23fba37886a84765342a44e404 Mon Sep 17 00:00:00 2001 From: Jairo Calmon Date: Thu, 4 Dec 2025 15:00:25 -0300 Subject: [PATCH 03/14] Add assert to confirm success o verify content --- test/clustertest/tests/JobIDTest.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/clustertest/tests/JobIDTest.cpp b/test/clustertest/tests/JobIDTest.cpp index 50d31620c..cd7b407a8 100644 --- a/test/clustertest/tests/JobIDTest.cpp +++ b/test/clustertest/tests/JobIDTest.cpp @@ -53,7 +53,7 @@ struct JobIDTest : tpunit::TestFixture { sleep(1); } - // make sure it actually succeeded. + // Make sure it actually succeeded. ASSERT_TRUE(success); // Create a job in the follower @@ -77,6 +77,9 @@ struct JobIDTest : tpunit::TestFixture { sleep(1); } + // Make sure it also succeeded. + ASSERT_TRUE(success); + // Create a new job in leader. response = leader.executeWaitVerifyContentTable(createCmd); From 8861406c6f4faee1d50d12fddc0ac0173189713f Mon Sep 17 00:00:00 2001 From: Jairo Calmon Date: Thu, 4 Dec 2025 15:00:56 -0300 Subject: [PATCH 04/14] Adjust errors from calling virtual functions from destructor --- test/lib/BedrockTester.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/lib/BedrockTester.cpp b/test/lib/BedrockTester.cpp index ec5c219de..49c422ff0 100644 --- a/test/lib/BedrockTester.cpp +++ b/test/lib/BedrockTester.cpp @@ -143,7 +143,8 @@ BedrockTester::~BedrockTester() { delete _db; } if (_serverPID) { - stopServer(); + // Note that we cannot call the subclass override in destructors + BedrockTester::stopServer(); } SFileExists(_args["-db"].c_str()) && unlink(_args["-db"].c_str()); @@ -304,7 +305,7 @@ string BedrockTester::startServer(bool wait) { // We've successfully opened a socket, so let's try and send a command. SData status("Status"); - auto result = executeWaitMultipleData({status}, 1, !wait); + auto result = executeWaitMultipleData({status}, 1, !wait); //NOLINT(clang-analyzer-optin.cplusplus.VirtualCall) if (result[0].methodLine == "200 OK") { return result[0].content; } From b2fd4617e97b4c2e78f43069272fe03826223df3 Mon Sep 17 00:00:00 2001 From: Jairo Calmon Date: Thu, 4 Dec 2025 15:01:17 -0300 Subject: [PATCH 05/14] Avoid setting variables and never using them --- test/tests/LibStuffTest.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/tests/LibStuffTest.cpp b/test/tests/LibStuffTest.cpp index 7e4c9078d..5a98d24ed 100644 --- a/test/tests/LibStuffTest.cpp +++ b/test/tests/LibStuffTest.cpp @@ -240,7 +240,7 @@ struct LibStuff : tpunit::TestFixture { "Content-Length: 5\r" "\r\n" "too short"; // only 'too s' read. - processed = SParseHTTP(recvBuffer.c_str(), recvBuffer.length(), methodLine, headers, content); + SParseHTTP(recvBuffer.c_str(), recvBuffer.length(), methodLine, headers, content); ASSERT_EQUAL(methodLine, "some method line"); ASSERT_EQUAL(content, "too s"); @@ -253,7 +253,7 @@ struct LibStuff : tpunit::TestFixture { "0123456789\r\n" "0\r\n" "\r\n"; - processed = SParseHTTP(recvBuffer.c_str(), recvBuffer.length(), methodLine, headers, content); + SParseHTTP(recvBuffer.c_str(), recvBuffer.length(), methodLine, headers, content); ASSERT_EQUAL(methodLine, "some method line"); ASSERT_EQUAL(content, "abcde0123456789"); @@ -262,7 +262,7 @@ struct LibStuff : tpunit::TestFixture { "\r\n" "6\r\n" // one too long. "abcde"; - processed = SParseHTTP(recvBuffer.c_str(), recvBuffer.length(), methodLine, headers, content); + SParseHTTP(recvBuffer.c_str(), recvBuffer.length(), methodLine, headers, content); ASSERT_EQUAL(methodLine, ""); ASSERT_EQUAL(content, ""); @@ -271,7 +271,7 @@ struct LibStuff : tpunit::TestFixture { "\r\n" "5\r\n" // exact without end. "abcde"; - processed = SParseHTTP(recvBuffer.c_str(), recvBuffer.length(), methodLine, headers, content); + SParseHTTP(recvBuffer.c_str(), recvBuffer.length(), methodLine, headers, content); ASSERT_EQUAL(methodLine, ""); ASSERT_EQUAL(content, ""); @@ -288,7 +288,7 @@ struct LibStuff : tpunit::TestFixture { "header2: value2a\n" "header3: value3\n" "\r\n"; - processed = SParseHTTP(recvBuffer.c_str(), recvBuffer.length(), methodLine, headers, content); + SParseHTTP(recvBuffer.c_str(), recvBuffer.length(), methodLine, headers, content); ASSERT_EQUAL(methodLine, "some method line"); ASSERT_EQUAL(headers["header1"], "value1"); ASSERT_EQUAL(headers["header2"], "value2a"); @@ -304,7 +304,7 @@ struct LibStuff : tpunit::TestFixture { "0123456789\r\n" "0\r\n" "\r\n"; - processed = SParseHTTP(recvBuffer.c_str(), recvBuffer.length(), methodLine, headers, content); + SParseHTTP(recvBuffer.c_str(), recvBuffer.length(), methodLine, headers, content); ASSERT_EQUAL(methodLine, ""); ASSERT_EQUAL(content, ""); @@ -317,7 +317,7 @@ struct LibStuff : tpunit::TestFixture { "0123456789\r\n" "0\r\n" "\r\n"; - processed = SParseHTTP(recvBuffer.c_str(), recvBuffer.length(), methodLine, headers, content); + SParseHTTP(recvBuffer.c_str(), recvBuffer.length(), methodLine, headers, content); ASSERT_EQUAL(methodLine, "some method line y"); ASSERT_EQUAL(content, "abcde"); // partial fail. @@ -330,7 +330,7 @@ struct LibStuff : tpunit::TestFixture { "0123456789\r\n" "0\r\n"; // "\r\n"; // missing last new line. - processed = SParseHTTP(recvBuffer.c_str(), recvBuffer.length(), methodLine, headers, content); + SParseHTTP(recvBuffer.c_str(), recvBuffer.length(), methodLine, headers, content); ASSERT_EQUAL(methodLine, ""); ASSERT_EQUAL(content, ""); } From d593b9199ad79009fe7308fa021273dc97817315 Mon Sep 17 00:00:00 2001 From: Jairo Calmon Date: Thu, 4 Dec 2025 15:02:02 -0300 Subject: [PATCH 06/14] Avoid unnecessary copy using strcpy --- test/tests/SQLiteNodeTest.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/tests/SQLiteNodeTest.cpp b/test/tests/SQLiteNodeTest.cpp index 046c5e48a..d62b7c87d 100644 --- a/test/tests/SQLiteNodeTest.cpp +++ b/test/tests/SQLiteNodeTest.cpp @@ -38,8 +38,7 @@ struct SQLiteNodeTest : tpunit::TestFixture { TEST(SQLiteNodeTest::testGetPeerByName)) { } // Filename for temp DB. - char filenameTemplate[17] = "br_sync_dbXXXXXX"; - char filename[17]; + char filename[17] = "br_sync_dbXXXXXX"; TestServer server; string peerList = "host1.fake:15555?nodeName=peer1,host2.fake:16666?nodeName=peer2,host3.fake:17777?nodeName=peer3,host4.fake:18888?nodeName=peer4"; @@ -47,7 +46,6 @@ struct SQLiteNodeTest : tpunit::TestFixture { void setup() { // This exposes just enough to test the peer selection logic. - strcpy(filename, filenameTemplate); int fd = mkstemp(filename); close(fd); dbPool = make_shared(10, filename, 1000000, 5000, 0); From 561c4331d3582cff687ffeedd5c7f938a53f57e2 Mon Sep 17 00:00:00 2001 From: Jairo Calmon Date: Thu, 4 Dec 2025 15:07:33 -0300 Subject: [PATCH 07/14] Replace assert with expect so it doesn't early return and leak memory --- test/tests/SSLTest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/tests/SSLTest.cpp b/test/tests/SSLTest.cpp index c9f4dc518..64ec73d5d 100644 --- a/test/tests/SSLTest.cpp +++ b/test/tests/SSLTest.cpp @@ -78,11 +78,11 @@ struct SSLTest : tpunit::TestFixture { } // Validate that the response is reasonable - ASSERT_EQUAL(transaction->response, 200); + EXPECT_EQUAL(transaction->response, 200); // Make sure that the response has a body. This differentiates it from the response to a CONNECT message // So that we can test we're looking at the actual proxied response and not just the response from the proxy itself. - ASSERT_TRUE(transaction->fullResponse.content.size()); + EXPECT_TRUE(transaction->fullResponse.content.size()); // Close the transaction. manager.closeTransaction(transaction); From 820b5943e2c9f9ef9e7d98a068fc6bcef2b7fbf8 Mon Sep 17 00:00:00 2001 From: Jairo Calmon Date: Thu, 4 Dec 2025 15:49:59 -0300 Subject: [PATCH 08/14] Remove unneeded variables --- test/clustertest/tests/ConflictSpamTest.cpp | 2 +- test/clustertest/tests/FutureExecutionTest.cpp | 4 ++-- test/clustertest/tests/LeadingTest.cpp | 2 +- test/clustertest/tests/UpgradeDBTest.cpp | 2 +- test/tests/LibStuffTest.cpp | 9 +-------- test/tests/jobs/DeleteJobTest.cpp | 1 - test/tests/jobs/RetryJobTest.cpp | 2 +- 7 files changed, 7 insertions(+), 15 deletions(-) diff --git a/test/clustertest/tests/ConflictSpamTest.cpp b/test/clustertest/tests/ConflictSpamTest.cpp index 9480b9a6b..ee0f4620d 100644 --- a/test/clustertest/tests/ConflictSpamTest.cpp +++ b/test/clustertest/tests/ConflictSpamTest.cpp @@ -40,7 +40,7 @@ struct ConflictSpamTest : tpunit::TestFixture { query["value"] = "sent-" + to_string(cmdNum); // Ok, send. - string result = brtester.executeWaitVerifyContent(query); + brtester.executeWaitVerifyContent(query); } } diff --git a/test/clustertest/tests/FutureExecutionTest.cpp b/test/clustertest/tests/FutureExecutionTest.cpp index 5b4aa5784..c15f93b87 100644 --- a/test/clustertest/tests/FutureExecutionTest.cpp +++ b/test/clustertest/tests/FutureExecutionTest.cpp @@ -31,7 +31,7 @@ struct FutureExecutionTest : tpunit::TestFixture { // Three seconds from now. query["commandExecuteTime"] = to_string(STimeNow() + 3000000); query["Query"] = "INSERT INTO test VALUES(" + SQ(50011) + ", " + SQ("sent_by_leader") + ");"; - string result = brtester.executeWaitVerifyContent(query, "202"); + string result = brtester.executeWaitVerifyContent(query, "202"); // Ok, Now let's wait a second sleep(1); @@ -75,7 +75,7 @@ struct FutureExecutionTest : tpunit::TestFixture { // And, there's a query to run, too, I guess. query["Query"] = "SELECT 1;"; - string result = brtester.executeWaitVerifyContent(query, "555 Timeout"); + brtester.executeWaitVerifyContent(query, "555 Timeout"); } } __FutureExecutionTest; diff --git a/test/clustertest/tests/LeadingTest.cpp b/test/clustertest/tests/LeadingTest.cpp index acf24f5f3..a75288c6f 100644 --- a/test/clustertest/tests/LeadingTest.cpp +++ b/test/clustertest/tests/LeadingTest.cpp @@ -83,7 +83,7 @@ struct LeadingTest : tpunit::TestFixture { BedrockTester& newLeader = tester->getTester(1); SData cmd("httpstimeout"); cmd["Connection"] = "forget"; - auto result = newLeader.executeWaitVerifyContent(cmd, "202"); + newLeader.executeWaitVerifyContent(cmd, "202"); } void restoreLeader() diff --git a/test/clustertest/tests/UpgradeDBTest.cpp b/test/clustertest/tests/UpgradeDBTest.cpp index 0af13bb66..2d203ff4f 100644 --- a/test/clustertest/tests/UpgradeDBTest.cpp +++ b/test/clustertest/tests/UpgradeDBTest.cpp @@ -26,7 +26,7 @@ struct UpgradeDBTest : tpunit::TestFixture { // This just verifies that the dbupgrade table was created by TestPlugin. SData query("Query"); query["Query"] = "INSERT INTO dbupgrade VALUES(" + SQ(1 + i) + ", " + SQ("val") + ");"; - string result = brtester.executeWaitVerifyContent(query, "200"); + brtester.executeWaitVerifyContent(query, "200"); } } } __UpgradeDBTest; diff --git a/test/tests/LibStuffTest.cpp b/test/tests/LibStuffTest.cpp index 5a98d24ed..ea3363f07 100644 --- a/test/tests/LibStuffTest.cpp +++ b/test/tests/LibStuffTest.cpp @@ -644,7 +644,6 @@ struct LibStuff : tpunit::TestFixture { string timeStamp3 = "2020-06-17"; string timeStamp4 = "2020-07-07"; string timeStamp5 = "2020-11-11"; - string timeStamp6 = "2020-01-01"; string octalTimestamp = "2019-09-03"; string notATimeStamp = "this is not a timestamp"; @@ -761,13 +760,7 @@ struct LibStuff : tpunit::TestFixture { ASSERT_EQUAL(result[2]["value"], "value3"); // Validate our exception handling. - bool threw = false; - try { - string s = result[0]["notacolumn"]; - } catch (const SException& e) { - threw = true; - } - ASSERT_TRUE(threw); + ASSERT_NO_THROW(result[0]["notacolumn"]); // Test aliased names. db.beginTransaction(SQLite::TRANSACTION_TYPE::SHARED); diff --git a/test/tests/jobs/DeleteJobTest.cpp b/test/tests/jobs/DeleteJobTest.cpp index 72d93fd6f..abe90e427 100644 --- a/test/tests/jobs/DeleteJobTest.cpp +++ b/test/tests/jobs/DeleteJobTest.cpp @@ -53,7 +53,6 @@ struct DeleteJobTest : tpunit::TestFixture { command["name"] = "child"; command["parentJobID"] = parentID; response = tester->executeWaitVerifyContentTable(command); - string childID = response["jobID"]; // Finish the parent command.clear(); diff --git a/test/tests/jobs/RetryJobTest.cpp b/test/tests/jobs/RetryJobTest.cpp index fb350130c..046a2b3ad 100644 --- a/test/tests/jobs/RetryJobTest.cpp +++ b/test/tests/jobs/RetryJobTest.cpp @@ -291,7 +291,7 @@ struct RetryJobTest : tpunit::TestFixture { // Get the nextRun value SQResult result; tester->readDB("SELECT nextRun FROM jobs WHERE jobID = " + jobID + ";", result); - string originalNextRun = result[0][0]; + ASSERT_FALSE(result.empty()); // Get the job command.clear(); From 1da7d2a6eddfc8b7d8d5d475a77f0629dd0cf1ed Mon Sep 17 00:00:00 2001 From: Jairo Calmon Date: Thu, 4 Dec 2025 16:05:21 -0300 Subject: [PATCH 09/14] Adjust throw assert --- test/tests/LibStuffTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/tests/LibStuffTest.cpp b/test/tests/LibStuffTest.cpp index ea3363f07..26b6b249b 100644 --- a/test/tests/LibStuffTest.cpp +++ b/test/tests/LibStuffTest.cpp @@ -760,7 +760,7 @@ struct LibStuff : tpunit::TestFixture { ASSERT_EQUAL(result[2]["value"], "value3"); // Validate our exception handling. - ASSERT_NO_THROW(result[0]["notacolumn"]); + ASSERT_ANY_THROW(result[0]["notacolumn"]); // Test aliased names. db.beginTransaction(SQLite::TRANSACTION_TYPE::SHARED); From b7d7e0bfe578b18455eea611b10c4a74a16451f3 Mon Sep 17 00:00:00 2001 From: Jairo Calmon Date: Thu, 4 Dec 2025 16:05:39 -0300 Subject: [PATCH 10/14] Remove unneeded copies --- libstuff/SDeburr.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libstuff/SDeburr.h b/libstuff/SDeburr.h index 7a52a895e..a7ee7eeeb 100644 --- a/libstuff/SDeburr.h +++ b/libstuff/SDeburr.h @@ -56,8 +56,8 @@ class SDeburr { static constexpr array UNICODE_TO_ASCII_MAP = []() constexpr { array map = {}; - auto mapCodePoints = [&map](const char* value, vector codePoints) { - for (auto codePoint : codePoints) { + auto mapCodePoints = [&map](const char* value, const vector& codePoints) { + for (const auto& codePoint : codePoints) { map[codePoint] = value; } }; From 6ce42dcb8a0bc85b4db57a49eda55a4815dad490 Mon Sep 17 00:00:00 2001 From: Jairo Calmon Date: Wed, 3 Dec 2025 18:33:27 -0300 Subject: [PATCH 11/14] Initial cmake integration --- CMakeLists.txt | 147 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..da62823ee --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,147 @@ +cmake_minimum_required(VERSION 3.10) +project(Bedrock) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +link_libraries("-fuse-ld=mold") + +# Find the clang-tidy executable first +find_program(CLANG_TIDY_EXECUTABLE NAMES clang-tidy-18) +if(CLANG_TIDY_EXECUTABLE) + # clang-tidy will automatically find and use the .clang-tidy config file + set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_EXECUTABLE}") +endif() + +# Amalgamation flags +set(AMALGAMATION_FLAGS " -Wno-unused-but-set-variable -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT -DSQLITE_ENABLE_NOOP_UPDATE -DSQLITE_MUTEX_ALERT_MILLISECONDS=20 -DHAVE_USLEEP=1 -DSQLITE_MAX_MMAP_SIZE=17592186044416ull -DSQLITE_SHARED_MAPPING -DSQLITE_ENABLE_NORMALIZE -DSQLITE_MAX_PAGE_COUNT=4294967294 -DSQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS -DSQLITE_DEFAULT_CACHE_SIZE=-51200 -DSQLITE_MAX_FUNCTION_ARG=32767 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=0 -DSQLITE_ENABLE_WAL_BIGHASH -DSQLITE_ENABLE_WAL2NOCKSUM") + +# Set our standard C++ compiler flags +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20 -DSQLITE_ENABLE_NORMALIZE -Wall -Werror -Wformat-security -Wno-unqualified-std-cast-call -Wno-sign-conversion -Wno-error=deprecated-declarations -Wunused-variable -fPIC") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c23 -fPIC ${AMALGAMATION_FLAGS}") + +if(DEFINED ENV{BEDROCK_OPTIM_COMPILE_FLAG}) + message(STATUS "Applying BEDROCK_OPTIM_COMPILE_FLAG compile flag: $ENV{BEDROCK_OPTIM_COMPILE_FLAG}") + # Adjust the optimization level without repeating it to avoid confusions + string(REGEX REPLACE "([\\/\\-]O3)" "$ENV{BEDROCK_OPTIM_COMPILE_FLAG}" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") + string(REGEX REPLACE "([\\/\\-]O3)" "$ENV{BEDROCK_OPTIM_COMPILE_FLAG}" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") + string(REGEX REPLACE "([\\/\\-]O2)" "$ENV{BEDROCK_OPTIM_COMPILE_FLAG}" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + string(REGEX REPLACE "([\\/\\-]O2)" "$ENV{BEDROCK_OPTIM_COMPILE_FLAG}" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") +else() + # Modify compile flags to change optimization level from O3 to O2 + string(REGEX REPLACE "([\\/\\-]O)3" "\\12" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") + string(REGEX REPLACE "([\\/\\-]O)3" "\\12" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") +endif() + +# Check if Git is available. This is good practice. +find_package(Git QUIET) +if(Git_FOUND) + # Execute the git command and store the output in GIT_REVISION + execute_process( + COMMAND git rev-parse HEAD + OUTPUT_VARIABLE GIT_REVISION + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + + # Shorten the hash to the first 10 characters, similar to grep -o '^.\{10\}' + string(SUBSTRING "${GIT_REVISION}" 0 10 GIT_REVISION) + message(STATUS "Git Revision: ${GIT_REVISION}") +else() + message(WARNING "Git not found. Unable to get revision hash.") + set(GIT_REVISION 1) +endif() + +option(ENABLE_BUILD_PROFILING "Enable build profiling" OFF) +if (ENABLE_BUILD_PROFILING) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftime-trace") +endif() + +# There files need GIT_REVISION +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/BedrockServer.cpp PROPERTIES COMPILE_OPTIONS "-DGIT_REVISION=${GIT_REVISION}") +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/main.cpp PROPERTIES COMPILE_OPTIONS "-DGIT_REVISION=${GIT_REVISION}") +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/plugins/MySQL.cpp PROPERTIES COMPILE_OPTIONS "-DGIT_REVISION=${GIT_REVISION}") + +# Set our include paths. We need this for the pre-processor to use to generate dependencies. +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/mbedtls/include) + +# We use the same library paths and required libraries for all binaries. +link_directories(${CMAKE_CURRENT_SOURCE_DIR}/mbedtls/library) + +# We use our project directory as a search path so we don't need "../../../.." all over the place. +set(CMAKE_INCLUDE_CURRENT_DIR "ON") + +# # Disable mbed tests and programs +# set(ENABLE_TESTING OFF CACHE BOOL "Build Mbed TLS tests") +# set(ENABLE_PROGRAMS OFF CACHE BOOL "Build Mbed TLS programs") + +# # Add the mbedtls directory as a subdirectory. +# # This executes its CMakeLists.txt and creates the necessary targets (like mbedcrypto, mbedtls, mbedx509). +# add_subdirectory(mbedtls) + +file(GLOB_RECURSE LIBSTUFF_SRC "${CMAKE_CURRENT_SOURCE_DIR}/libstuff/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/libstuff/qrf.c" "${CMAKE_CURRENT_SOURCE_DIR}/libstuff/sqlite3.c") +add_library(libstuff STATIC ${LIBSTUFF_SRC}) +set_target_properties(libstuff PROPERTIES PREFIX "") + +# Make an explicif list of files since the use of globs can be considered a bad practice +set(BEDROCK_SRC + "${CMAKE_CURRENT_SOURCE_DIR}/BedrockBlockingCommandQueue.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/BedrockCommand.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/BedrockCommandQueue.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/BedrockConflictManager.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/BedrockCore.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/BedrockPlugin.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/BedrockServer.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/BedrockTimeoutCommandQueue.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/PageLockGuard.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/VMTouch.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/benchmarks/SDeburrBench.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/benchmarks/main.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/plugins/Cache.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/plugins/DB.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/plugins/Jobs.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/plugins/MySQL.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/sqlitecluster/SQLite.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/sqlitecluster/SQLiteClusterMessenger.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/sqlitecluster/SQLiteCommand.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/sqlitecluster/SQLiteCore.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/sqlitecluster/SQLiteNode.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/sqlitecluster/SQLitePeer.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/sqlitecluster/SQLitePool.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/sqlitecluster/SQLiteUtils.cpp" +) + +add_library(libbedrock STATIC ${BEDROCK_SRC}) +set_target_properties(libbedrock PROPERTIES PREFIX "")# OUTPUT_NAME auth LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/auth") +target_link_libraries(libbedrock PUBLIC libstuff) +target_link_libraries(libbedrock INTERFACE dl pcre2-8 pthread mbedtls mbedx509 mbedcrypto z m) + +# Build bedrock executable +add_executable(bedrock "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") +target_link_libraries(bedrock PRIVATE libbedrock) + +# Common files for tests and cluster tests +file(GLOB_RECURSE LIBTEST_SRC "${CMAKE_CURRENT_SOURCE_DIR}/test/lib/*.cpp") + +# Test only include main, tests and lib (should not include clustertest) +file(GLOB_RECURSE TESTS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/test/tests/*.cpp") +add_executable(test "${LIBTEST_SRC}" "${TESTS_SRC}" "${CMAKE_CURRENT_SOURCE_DIR}/test/main.cpp") +target_link_libraries(test PRIVATE libbedrock) + +# And the same for cluster tests minus the ordinary tests +file(GLOB_RECURSE CLUSTERTEST_SRC "${CMAKE_CURRENT_SOURCE_DIR}/test/clustertest/*.cpp") +add_executable(clustertest "${LIBTEST_SRC}" "${CLUSTERTEST_SRC}" "${CMAKE_CURRENT_SOURCE_DIR}/test/tests/jobs/JobTestHelper.cpp") +target_link_libraries(clustertest PRIVATE libbedrock) + +# Benchmarks binary (separate from unit tests) under top-level benchmarks/ +file(GLOB_RECURSE BENCH_SRC "${CMAKE_CURRENT_SOURCE_DIR}/benchmarks/*.cpp") +add_executable(bench "${BENCH_SRC}" "${CMAKE_CURRENT_SOURCE_DIR}/test/lib/tpunit++.cpp") +target_link_libraries(bench PRIVATE libbedrock) + +# The rule to build TestPlugin +add_library(testplugin SHARED "test/clustertest/testplugin/TestPlugin.cpp" "test/clustertest/testplugin/ExternPointer.cpp") +set_target_properties(testplugin PROPERTIES PREFIX "" OUTPUT_NAME testplugin LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") +target_compile_options(testplugin PRIVATE -Wall -Werror -Wformat-security -Wno-unqualified-std-cast-call -Wno-sign-conversion -fPIC) +target_link_libraries(testplugin INTERFACE libbedrock) + From 356e5d359a73aba1bcb2f1cfa94e3cc97dc96507 Mon Sep 17 00:00:00 2001 From: Jairo Calmon Date: Thu, 4 Dec 2025 11:57:42 -0300 Subject: [PATCH 12/14] Ignore linting for tpunit++ --- CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index da62823ee..bd41fa8f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,11 +58,14 @@ if (ENABLE_BUILD_PROFILING) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftime-trace") endif() -# There files need GIT_REVISION +# These files need GIT_REVISION set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/BedrockServer.cpp PROPERTIES COMPILE_OPTIONS "-DGIT_REVISION=${GIT_REVISION}") set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/main.cpp PROPERTIES COMPILE_OPTIONS "-DGIT_REVISION=${GIT_REVISION}") set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/plugins/MySQL.cpp PROPERTIES COMPILE_OPTIONS "-DGIT_REVISION=${GIT_REVISION}") +# These files are should ignore linting +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/test/lib/tpunit++.cpp PROPERTIES SKIP_LINTING ON) + # Set our include paths. We need this for the pre-processor to use to generate dependencies. include_directories(${CMAKE_CURRENT_SOURCE_DIR}/mbedtls/include) From 3f2ee31a304000fb82258361b60d3ecf2ae72667 Mon Sep 17 00:00:00 2001 From: Jairo Calmon Date: Thu, 4 Dec 2025 14:57:27 -0300 Subject: [PATCH 13/14] Adjust cmake for object target for test lib --- CMakeLists.txt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bd41fa8f6..11b6f4e61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,18 +124,19 @@ target_link_libraries(libbedrock INTERFACE dl pcre2-8 pthread mbedtls mbedx509 m add_executable(bedrock "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") target_link_libraries(bedrock PRIVATE libbedrock) -# Common files for tests and cluster tests +# Common files for tests and cluster tests (compile to object library and link after) file(GLOB_RECURSE LIBTEST_SRC "${CMAKE_CURRENT_SOURCE_DIR}/test/lib/*.cpp") +add_library(libtest_objects OBJECT ${LIBTEST_SRC}) # Test only include main, tests and lib (should not include clustertest) file(GLOB_RECURSE TESTS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/test/tests/*.cpp") -add_executable(test "${LIBTEST_SRC}" "${TESTS_SRC}" "${CMAKE_CURRENT_SOURCE_DIR}/test/main.cpp") -target_link_libraries(test PRIVATE libbedrock) +add_executable(test "${TESTS_SRC}" "${CMAKE_CURRENT_SOURCE_DIR}/test/main.cpp") +target_link_libraries(test PRIVATE libbedrock libtest_objects) # And the same for cluster tests minus the ordinary tests file(GLOB_RECURSE CLUSTERTEST_SRC "${CMAKE_CURRENT_SOURCE_DIR}/test/clustertest/*.cpp") -add_executable(clustertest "${LIBTEST_SRC}" "${CLUSTERTEST_SRC}" "${CMAKE_CURRENT_SOURCE_DIR}/test/tests/jobs/JobTestHelper.cpp") -target_link_libraries(clustertest PRIVATE libbedrock) +add_executable(clustertest "${CLUSTERTEST_SRC}" "${CMAKE_CURRENT_SOURCE_DIR}/test/tests/jobs/JobTestHelper.cpp") +target_link_libraries(clustertest PRIVATE libbedrock libtest_objects) # Benchmarks binary (separate from unit tests) under top-level benchmarks/ file(GLOB_RECURSE BENCH_SRC "${CMAKE_CURRENT_SOURCE_DIR}/benchmarks/*.cpp") From 25fe8f561a1afe7ca12466e8fd3b275de4ca3d59 Mon Sep 17 00:00:00 2001 From: Jairo Calmon Date: Thu, 4 Dec 2025 15:23:22 -0300 Subject: [PATCH 14/14] Add build folder to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index aa4524ed3..072bd92dc 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ test/bedrocktest_* test/clustertest/cluster_node_?_bedrocktest* bedrock .build +build libbedrock.a libstuff.a sqlitecluster/sqlitecluster