Skip to content

build(cmake): minimal fixes in CMakeLists.txt for transitive restbed headers, i2pcommon, and versioning#298

Closed
jolavillette wants to merge 9 commits into
RetroShare:masterfrom
jolavillette:CMakeMigration-Modular
Closed

build(cmake): minimal fixes in CMakeLists.txt for transitive restbed headers, i2pcommon, and versioning#298
jolavillette wants to merge 9 commits into
RetroShare:masterfrom
jolavillette:CMakeMigration-Modular

Conversation

@jolavillette
Copy link
Copy Markdown
Contributor

build(cmake): minimal fixes in CMakeLists.txt for transitive restbed headers, i2pcommon, and versioning

This PR stabilizes the CMake configuration of libretroshare to support downstream modular builds (such as retroshare-gui and retroshare-service).

To ensure maximum stability and ease of review, the modifications made to the CMakeLists files are kept strictly minimal and highly targeted:

  • Transitive Headers (1 line change): Promoted the restbed include directory to PUBLIC in CMakeLists.txt so that downstream modules cleanly inherit the HTTP/JSON API headers without duplicate include paths.
  • Link Fixes (2 lines change): Reactivated the compilation of util/i2pcommon.cpp/.h under CMake, resolving undefined reference linking errors in downstream GUI settings panels.
  • Version Display (minimal additions):
    Directed the GUI human-readable version query to run in the parent directory's .git if present, ensuring the GUI gets the correct overall application version instead of submodule tags.
    Added the RS_LIB_VERSION_HASH compile definition on the core target, fixing the [version not available] display bug in the about box.

All changes are non-intrusive and strictly limited to resolving compile/link-time blockers.

@jolavillette jolavillette mentioned this pull request May 18, 2026
Copy link
Copy Markdown
Contributor

@G10h4ck G10h4ck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good things intermixed with wrong stuff, @jolavillette please fix them and answhere the inline questions ;-)

hasInput = True
if 'out' in tmpD:
tmpParam._out = True
hasOutput = True
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change seems unrelated to the PR description, what it is supposed to do?

Copy link
Copy Markdown
Contributor Author

@jolavillette jolavillette Jun 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for reviewing this PR. Note that since I pushed it I managed to compile also on Windows and MacOS. I had to make a few more changes in some CMakeLists.txt files. I just pushed the new cross platform PR on github: see #304

Please understand that even if I did my best along the development and cross platform testing of this PR to closely monitor what was going on, the replies below were AI generated,

About json-pi generator:
This fixes a crash of the JSON API generator with some Doxygen versions (especially on Windows/macOS). The original code accesses tmpPN.text directly, which returns None when the XML node contains sub-elements instead of plain text (behavior varies across Doxygen versions). Using getText(tmpPN) (which does "".join(e.itertext())) is more robust. The if pName in paramsMap guard prevents a KeyError if Doxygen generates unexpected entries.

Comment thread src/pqi/sslfns.h
@@ -1,4 +1,4 @@
/*******************************************************************************
/*******************************************************************************
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The line ending was wrong?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, there was trailing whitespace at end of line. Automatic cleanup by the editor. Cosmetic only, no functional impact.

Comment thread src/pqi/sslfns.h
#ifdef X509_EXTENSIONS
#undef X509_EXTENSIONS
#endif

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change seems unrelated to the PR description, what it is supposed to do?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a required fix for Windows compilation. Windows headers (<wincrypt.h>, pulled in transitively via system headers) define X509_NAME and X509_EXTENSIONS as preprocessor macros, which conflicts with their use as type identifiers in function signatures declared in sslfns.h (e.g. SignX509Certificate(X509_NAME *issuer, ...)). Without these #undef, compilation fails on Windows/MSVC.

This is a classic Windows compatibility pattern, also used by OpenSSL itself.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in that case the #if should be platform specific, like #if def(WINDOWS) && def(X509_EXTENSIONS) it also makes more explicit the intent of code, imagine reading that 2 years from now, surely you would exclaim WTF is this? also having some comment near this kind of stuff, makes it even more future readable. So please apply this adjustments to all the similar #ifdef introduced

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I have wrapped the #undef inside #if defined(WINDOWS_SYS) && defined(X509_EXTENSIONS) to make it strictly platform-specific. I also added an explicit comment explaining that Windows headers (<wincrypt.h>) define this as a macro which conflicts with RetroShare types.

Comment thread src/retroshare/rstor.h
#ifdef ERROR
#undef ERROR
#endif

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change seems unrelated to the PR description, what it is supposed to do?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as previous point: on Windows, <wingdi.h> (included transitively via <windows.h>) does #define ERROR 0. This breaks enum class members using ERROR as an enumerator, such as RsTorHiddenServiceStatus::ERROR and RsTorConnectivityStatus::ERROR. The preprocessor replaces ERROR with 0, causing a compilation error.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see previous comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Similarly, I wrapped this inside #if defined(WINDOWS_SYS) && defined(ERROR) and added a comment explaining the conflict with <wingdi.h>.

Comment thread src/util/rsdebug.h
#ifdef ERROR
#undef ERROR
#endif

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change seems unrelated to the PR description, what it is supposed to do?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as previous points. RsLoggerCategories::ERROR is broken by the Windows macro #define ERROR 0. The #undef is required for rsdebug.h to compile on Windows.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see previous comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Same as the previous point, the #undef is now platform-specific with an explanatory comment.

Comment thread CMakeLists.txt
${CMAKE_CURRENT_BINARY_DIR}/../supportlibs/librnp/Build/src/libsexpp
target_link_directories(${PROJECT_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../supportlibs/librnp/Build/src/lib
${CMAKE_CURRENT_SOURCE_DIR}/../supportlibs/librnp/Build/src/libsexpp
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the Build directory name always the same?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Build directory is created by the librnp build script (supportlibs/librnp) and its name is hardcoded in that script. It's the same name on all 3 platforms.

The change from CMAKE_CURRENT_BINARY_DIR to CMAKE_CURRENT_SOURCE_DIR is because librnp is built outside of libretroshare's CMake build tree (via a separate script), so its build artifacts live in the source tree, not in CMake's build directory.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, having a short comment about that would be helpful ;-)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I have added a short comment explaining that the Build directory name is hardcoded in librnp's custom external build script.

Comment thread CMakeLists.txt
json-c
bz2
z
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you are changing the linking of all those libraries from private to public, that means that ALL symbols will be visible when linking against libretroshare, that is unwanted also it raise an error like "too many symbols" on some platforms. Also I think libretroshare has no reason to expose all those symbols, if some downstream user need them, they will need to link to those libraries by themselves.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, PUBLIC is too broad and exposes headers/symbols unnecessarily. The reason we switched to PUBLIC was to fix downstream link errors on Windows. However, the root cause wasn't PRIVATE itself (CMake does propagate PRIVATE static dependencies for linking), but rather the use of target_link_directories(PRIVATE), which didn't propagate the -L search paths to the downstream executables.

I will revert to PRIVATE. To fix the Windows link errors properly, I will remove target_link_directories and instead link directly to the absolute paths of these static libraries (e.g., ${CMAKE_CURRENT_SOURCE_DIR}/.../librnp.a). This allows CMake to correctly resolve the libraries for downstream consumers without polluting the public interface.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems legit

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I reverted it to PRIVATE. To fix the downstream Windows link errors cleanly, I removed target_link_directories and instead linked directly to the absolute paths of the static libraries (e.g., librnp.a). This prevents exposing symbols unnecessarily.

Comment thread CMakeLists.txt
" ${CMAKE_CURRENT_SOURCE_DIR}/src/tests"
" ${CMAKE_CURRENT_SOURCE_DIR}/src/unused"
" ${CMAKE_CURRENT_SOURCE_DIR}/src/unfinished\n" )
if(NOT EXISTS "${JSON_API_GENERATOR_DOXYFILE}")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the conditional? In which case do you want it to not be overridden by the updated one?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without this condition, every CMake invocation (even a simple cmake --build that triggers a reconfigure) re-executes file(APPEND ...) and duplicates the OUTPUT_DIRECTORY, INPUT, EXCLUDE lines in the Doxyfile. After N reconfigurations, the file contains N copies of those directives, which generates Doxygen warnings and can cause unexpected behavior.

The original file(COPY ...) + file(APPEND ...) runs at every configure step, not just the first time. The condition prevents accumulation.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the original is copied and then the directives appended every-time, how is it possible for the directives to accumulate?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The accumulation happens because CMake's file(COPY) skips the copy if the destination file is newer. Since file(APPEND) modifies the destination, its timestamp becomes newer than the original. On the next CMake run, COPY is silently skipped, but APPEND runs again, duplicating the text. To fix this robustly, I have removed the if(NOT EXISTS) check and completely refactored the logic to use file(READ), followed by a string(APPEND) in memory, and finally a single file(WRITE). This prevents any accumulation.

Comment thread CMakeLists.txt
set(BUILD_TESTS OFF CACHE BOOL "Do not build restbed tests")
set(BUILD_SSL OFF CACHE BOOL "Do not build restbed SSL support")
set(BUILD_SHARED_LIBRARY OFF)
set(BUILD_SHARED_LIBS OFF)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the two of them needed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BUILD_SHARED_LIBS is the standard CMake variable (honored by add_library() when no type is specified). BUILD_SHARED_LIBRARY is a custom variable used specifically by restbed's CMakeLists. Both are needed because restbed uses its own convention on top of the standard CMake one.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it necessary to hardcode disabling them? What if a downstream libretroshare user what to link dinamically? Having the linker linking also the .so should not harm.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I have removed the hardcoded OFF values. They are now dynamically set to mirror RetroShare's library preference (${RS_LIBRETROSHARE_SHARED}). Downstream users can now link dynamically if they want.

Comment thread CMakeLists.txt
GIT_PROGRESS TRUE
TIMEOUT 10
# EXCLUDE_FROM_ALL # Available only in CMake >= 3.28
PATCH_COMMAND sed -i -e "s|/wd4251||g" -e "s|VERSION 3.1.0|VERSION 3.5.0|g" CMakeLists.txt
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this line supposed to do? At first glange it is quite brittle to hot patching CMake files line that, but above all why?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line does two things:

Removes /wd4251: this is an MSVC flag (/wd = disable warning) that restbed puts in its CMakeLists. This flag causes an error with GCC/Clang (which don't recognize it). Since we use FetchContent on all platforms, it must be removed on non-MSVC platforms.
Changes VERSION 3.1.0 → VERSION 3.5.0: restbed's CMakeLists specifies cmake_minimum_required(VERSION 3.1.0), which triggers a deprecation warning with CMake ≥ 3.27 (old policies are deprecated). Bumping to 3.5.0 silences this warning.
You're right that it's brittle — it breaks if restbed changes those exact strings in an update.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least a comment is needed explaining what is going on, also an upstream PR is the right thing to do

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I have added an explanatory comment above the command clarifying that the sed patch removes the MSVC-specific /wd4251 flag (which breaks GCC/Clang builds) and bumps the CMake VERSION to 3.5.0 to suppress deprecation warnings. I will also submit an upstream PR to restbed separately to fix this at the source.

@G10h4ck
Copy link
Copy Markdown
Contributor

G10h4ck commented Jun 2, 2026

Thank you for reviewing this PR. Note that since I pushed it I managed to compile also on Windows and MacOS. I had to make a few more changes in some CMakeLists.txt files. I just pushed the new cross platform PR on github: see #304

@jolavillette should I keep reviewing this code or the #304 ? Please one thing at time so we avoid wasting code review time

@jolavillette
Copy link
Copy Markdown
Contributor Author

jolavillette commented Jun 2, 2026

The changes following your comments are in 304, not 298.
I am sorry for the mess.
304 was built on top of 298.
It seemed reasonnable to me to proceed step by step and I chose to implemente the cmake migration for windows first and then macos.
I now realized that handling macos first would probably have been a better idea.
304 does not add many changes in libretroshare.
It would be better if you can switch to 304 from now.

@G10h4ck
Copy link
Copy Markdown
Contributor

G10h4ck commented Jun 2, 2026

should this be closed then ?

@jolavillette jolavillette deleted the CMakeMigration-Modular branch June 5, 2026 05:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants