Skip to content

build(cmake): Add support for building library targets that contain source files and linked libraries.#36

Merged
Bill-hbrhbr merged 17 commits intoy-scope:mainfrom
Bill-hbrhbr:add-support-for-libs-with-src
Mar 16, 2025
Merged

build(cmake): Add support for building library targets that contain source files and linked libraries.#36
Bill-hbrhbr merged 17 commits intoy-scope:mainfrom
Bill-hbrhbr:add-support-for-libs-with-src

Conversation

@Bill-hbrhbr
Copy link
Collaborator

@Bill-hbrhbr Bill-hbrhbr commented Mar 6, 2025

Description

Expanded and updated the arglist of cpp_library():

# @param NAME
# @param NAMESPACE
# @param PUBLIC_HEADERS
# @param PRIVATE_SOURCES
# @param PUBLIC_LINK_LIBRARIES
# @param PRIVATE_LINK_LIBRARIES
# @parms TESTS_SOURCES
# @param [BUILD_INCLUDE_DIR="${PROJECT_SOURCE_DIR}/src"]

Added a helper function check_if_header_only() for two functionalities:

  • Enforce that there are only header files inside PUBLIC_HEADERS
  • Check whether there are header files inside PRIVATE_SOURCES
    • If yes, build a static/shared library target
    • If no, build an interface library target

Checklist

  • The PR satisfies the contribution guidelines.
  • This is a breaking change and that has been indicated in the PR title, OR this isn't a
    breaking change.
  • Necessary docs have been updated, OR no docs need to be updated.

Validation performed

No tests needed.

Summary by CodeRabbit

  • New Features
    • Introduced new build options allowing users to choose shared library builds and to enable testing.
    • Enhanced library configuration to better distinguish header-only from full implementation libraries with improved error notifications.
    • Refined the public interfaces for container and error-handling modules to ensure a clearer and more robust integration.

@Bill-hbrhbr Bill-hbrhbr requested a review from a team as a code owner March 6, 2025 15:42
@coderabbitai
Copy link

coderabbitai bot commented Mar 6, 2025

Walkthrough

This pull request introduces a new helper function, check_if_header_only, to verify if a list of files consists solely of header files. The cpp_library function is updated with new parameters—including PUBLIC_HEADERS, PRIVATE_SOURCES, and library linking options—and its header validation logic now calls the new helper. Additionally, global CMake options for shared library builds and testing are added, and individual library configurations in the containers and error_handling modules are updated to integrate the new public header declarations.

Changes

File(s) Summary of Changes
CMake/ystdlib-cpp-helpers.cmake - Added check_if_header_only function for header validation.
- Updated cpp_library signature: added PUBLIC_HEADERS, PRIVATE_SOURCES, PUBLIC_LINK_LIBRARIES, and PRIVATE_LINK_LIBRARIES.
- Modified logic to validate headers, handle errors, and update library aliasing and unit test linking.
CMakeLists.txt - Added new options: BUILD_SHARED_LIBS (default OFF) and YSTDLIB_CPP_BUILD_TESTING (default ON).
- Removed the previous placement of the testing tree option.
src/ystdlib/containers/CMakeLists.txt - Updated cpp_library call: renamed NAME from container to containers.
- Added PUBLIC_HEADERS parameter with Array.hpp.
- Adjusted formatting for TESTS_SOURCES.
src/ystdlib/error_handling/CMakeLists.txt - Introduced a PUBLIC_HEADERS section including ErrorCode.hpp as a public header.

Sequence Diagram(s)

sequenceDiagram
    participant C as cpp_library
    participant H as check_if_header_only
    participant L as Library Builder
    participant U as Unit Test Linker

    C->>H: Validate PUBLIC_HEADERS and PRIVATE_SOURCES
    H-->>C: Return header-only status (or first invalid file)
    alt All headers are valid
        C->>L: Create interface or regular library based on header status
        L-->>C: Library target created
        C->>U: Link unit tests with the new alias target
    else Invalid header detected
        C-->>C: Trigger fatal error with invalid header detail
    end
Loading

Possibly Related PRs

Suggested Reviewers

  • kirkrodrigues
  • LinZhihao-723
  • davidlion

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2c1f968 and f1b792d.

📒 Files selected for processing (1)
  • CMake/ystdlib-cpp-helpers.cmake (4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: lint-check (macos-15)
  • GitHub Check: lint-check (ubuntu-24.04)
🔇 Additional comments (9)
CMake/ystdlib-cpp-helpers.cmake (9)

1-15: Good implementation of the header-only check function

The new check_if_header_only function is well-structured with clear parameter documentation and follows the suggestion to return early when a non-header file is found. This improves efficiency and readability.

However, the regex only matches .h and .hpp extensions, omitting .inc which was in line with a previous comment from davidlion.


25-32: Clear parameter documentation for the updated function

The documentation for the new parameters is concise and matches the implementation, making it easy to understand what the function expects.


39-46: Parameter names are clear and consistent

The parameter names follow a consistent pattern (PUBLIC_, PRIVATE_) and match the CMake naming conventions as suggested in previous reviews. The BUILD_INCLUDE_DIR parameter has been properly renamed from LIB_BUILD_INTERFACE.


49-50: Good use of a variable for the alias target name

Storing the alias target name in a variable improves maintainability and reduces the risk of inconsistencies when using it throughout the function.


51-56: Improved error handling for missing BUILD_INCLUDE_DIR

The code properly checks if BUILD_INCLUDE_DIR is missing and provides a useful error message that now includes the target name. The default value is set correctly when the parameter is not defined.


58-64: Good validation of PUBLIC_HEADERS

The check ensures that all files in PUBLIC_HEADERS are actual header files, which prevents potential build issues when users incorrectly specify source files as headers.


66-91: Robust library type determination logic

The implementation now properly distinguishes between interface (header-only) libraries and regular libraries based on the content of PRIVATE_SOURCES. The comment about BUILD_SHARED_LIBS is accurate and aligns with the CMake documentation.

For regular libraries, all sources (both PUBLIC_HEADERS and PRIVATE_SOURCES) are correctly added as PRIVATE sources to the target, while maintaining the appropriate include directory visibility.


93-100: Clear separation of PUBLIC and PRIVATE link libraries

The updated linking logic clearly distinguishes between public and private dependencies, which helps manage the library's dependency graph and prevents unnecessary transitive dependencies.


111-111: Consistent use of alias target in test linking

Using the alias target variable ensures consistency between the main library target and its usage in tests.

Also applies to: 124-124


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
CMake/ystdlib-cpp-helpers.cmake (2)

8-9: Consider expanding header file extension detection

The current regex only handles .h, .hpp, and .inc extensions. You might want to consider other common C++ header extensions like .hxx, .h++, or .tpp for template implementations.

-        if(${src_file} MATCHES ".*\\.(h|hpp|inc)")
+        if(${src_file} MATCHES ".*\\.(h|hpp|inc|hxx|h\\+\\+|tpp)")

85-85: Consider adding flexibility for dependency visibility

Currently, all dependencies are linked with PUBLIC visibility. Consider allowing PRIVATE or INTERFACE linkage for dependencies that don't need to be exposed to consumers of the library.

-    target_link_libraries(${arg_cpp_lib_NAME} PUBLIC ${arg_cpp_lib_DEPENDS})
+    # Split dependencies into PUBLIC and PRIVATE if needed
+    target_link_libraries(${arg_cpp_lib_NAME} PUBLIC ${arg_cpp_lib_DEPENDS})

In the future, you might want to expand this to allow specifying the visibility for each dependency:

# Example enhancement for future consideration
function(cpp_library)
    # ... existing parameters ...
    set(multiValueArgs
        # ... existing multi-value args ...
        PUBLIC_DEPENDS
        PRIVATE_DEPENDS
        INTERFACE_DEPENDS
    )
    # ...
    
    # Link with appropriate visibility
    if(arg_cpp_lib_PUBLIC_DEPENDS)
        target_link_libraries(${arg_cpp_lib_NAME} PUBLIC ${arg_cpp_lib_PUBLIC_DEPENDS})
    endif()
    if(arg_cpp_lib_PRIVATE_DEPENDS)
        target_link_libraries(${arg_cpp_lib_NAME} PRIVATE ${arg_cpp_lib_PRIVATE_DEPENDS})
    endif()
    if(arg_cpp_lib_INTERFACE_DEPENDS)
        target_link_libraries(${arg_cpp_lib_NAME} INTERFACE ${arg_cpp_lib_INTERFACE_DEPENDS})
    endif()
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 95d89d1 and 1c47e59.

📒 Files selected for processing (2)
  • CMake/ystdlib-cpp-helpers.cmake (4 hunks)
  • CMakeLists.txt (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: lint-check (ubuntu-24.04)
🔇 Additional comments (4)
CMakeLists.txt (1)

46-47: LGTM - Added standard CMake option for shared libraries

This is a standard CMake option that controls whether libraries are built as shared (.so/.dll) or static (.a/.lib) by default. The option is appropriately documented and placed in a logical location in the file.

CMake/ystdlib-cpp-helpers.cmake (3)

1-18: Well-implemented helper function for detecting header-only libraries

The function correctly identifies header-only libraries by removing header file extensions and checking if any source files remain. The implementation is clean and the function is well-documented.


28-44: LGTM - Updated function signature with new parameters

The function parameters have been appropriately expanded to support the new functionality. The documentation and parameter declarations are well aligned.


59-83: LGTM - Well-implemented conditional library creation

The implementation correctly differentiates between header-only libraries (which need to be INTERFACE) and libraries with source files. The include directories and compile features are set with appropriate visibility modifiers.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
CMake/ystdlib-cpp-helpers.cmake (2)

1-18: Well-structured header-only detection logic

The check_if_header_only_library function is implemented with clear logic to determine if a library consists only of header files. It correctly identifies and filters out common header file extensions.

For additional robustness, consider extending the pattern to include other possible header extensions like .hxx or .h++, though this is not critical for most projects.

-        if(${src_file} MATCHES ".*\\.(h|hpp|inc)")
+        if(${src_file} MATCHES ".*\\.(h|hpp|inc|hxx|h\\+\\+)")

61-83: Library creation logic requires clarification

The implementation correctly handles both header-only and regular libraries, but some aspects could be clearer:

  1. When creating a non-interface library, the empty string parameter to add_library() deserves explanation:
-        add_library(${arg_cpp_lib_NAME} "") # Library type determined by BUILD_SHARED_LIBS
+        # Empty string makes library type determined by BUILD_SHARED_LIBS option
+        add_library(${arg_cpp_lib_NAME} "")
  1. Consider adding a comment explaining the different visibility levels for include directories:
        target_include_directories(
            ${arg_cpp_lib_NAME}
            PUBLIC  # Public visibility for non-header-only libraries to expose headers
                "$<BUILD_INTERFACE:${arg_cpp_lib_LIB_BUILD_INTERFACE}>"
        )
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1c47e59 and 8015150.

📒 Files selected for processing (1)
  • CMake/ystdlib-cpp-helpers.cmake (4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: lint-check (macos-15)
🔇 Additional comments (4)
CMake/ystdlib-cpp-helpers.cmake (4)

28-30: LGTM: Properly documented function parameters

The new parameters for the cpp_library function are clearly documented, making the function's usage apparent to users.


41-43: LGTM: Parameters correctly added to multiValueArgs

The parameters are appropriately categorized as multi-value arguments, which is consistent with their purpose.


59-60: LGTM: Good use of helper function

Excellent approach to separate the header-only detection logic into a reusable function.


85-85: LGTM: Proper library dependency handling

Correctly links the library with its dependencies, regardless of whether it's a header-only or regular library.

@Bill-hbrhbr
Copy link
Collaborator Author

@coderabbitai
CMake/ystdlib-cpp-helpers.cmake (2)
1-18: Well-structured header-only detection logic
currently we only lint h, hpp, cpp files. no need to add more to the scope

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
CMake/ystdlib-cpp-helpers.cmake (2)

63-86: Consider parameter validation for SOURCES and HEADERS

The conditional logic for creating either an interface or standard library works well. However, there's no validation to ensure arg_cpp_lib_SOURCES or arg_cpp_lib_HEADERS are defined before use, similar to the check for LIB_BUILD_INTERFACE.

+    # Check if required parameters are provided
+    if(NOT DEFINED arg_cpp_lib_SOURCES)
+        set(arg_cpp_lib_SOURCES "")
+    endif()
+
+    if(NOT DEFINED arg_cpp_lib_HEADERS)
+        set(arg_cpp_lib_HEADERS "")
+    endif()
+
     check_if_header_only_library(arg_cpp_lib_SOURCES _IS_INTERFACE_LIB)

74-79: Consider relocating headers to PUBLIC sources

Currently, headers are included in the PRIVATE section of target_sources. If these are API headers that should be visible to dependents, consider moving them to the PUBLIC section.

     target_sources(
         ${arg_cpp_lib_NAME}
+        PUBLIC
+            ${arg_cpp_lib_HEADERS}
         PRIVATE
-            ${arg_cpp_lib_HEADERS}
             ${arg_cpp_lib_SOURCES}
     )
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8015150 and 352040a.

📒 Files selected for processing (1)
  • CMake/ystdlib-cpp-helpers.cmake (4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: lint-check (ubuntu-24.04)
  • GitHub Check: lint-check (macos-15)
🔇 Additional comments (5)
CMake/ystdlib-cpp-helpers.cmake (5)

1-18: Well-implemented header-only library check function

The check_if_header_only_library function is well-structured and correctly identifies libraries that consist solely of header files by iterating through the source list and removing header files.


28-31: Good documentation of new parameters

Clear documentation of the newly added parameters enhances the function's usability.


42-45: Appropriate parameter registration

The new parameters are properly registered in the multiValueArgs list, which is necessary for cmake_parse_arguments to process them correctly.


61-62: Good use of the new check function

Appropriately using the newly defined function to determine library type.


88-94: Proper linkage of dependencies

The update correctly handles both public and private dependencies, which is essential for libraries with source files.

@coderabbitai
Copy link

coderabbitai bot commented Mar 6, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

I need to look at the check_if_header_only_library function to understand the context of your comment. Let me fetch that code.


🏁 Script executed:

#!/bin/bash
# Fetch the content of the CMake/ystdlib-cpp-helpers.cmake file, focusing on lines 1-18
cat CMake/ystdlib-cpp-helpers.cmake | head -18

Length of output: 729


@Bill-hbrhbr Thank you for the feedback! I see the header-only detection logic checks for .h, .hpp, and .inc extensions. I understand that since you only lint .h, .hpp, and .cpp files in your project, there's no need to expand the detection scope further. The current implementation is appropriately focused on your project's needs.


✏️ Learnings added
Learnt from: Bill-hbrhbr
URL: https://github.com/y-scope/ystdlib-cpp/pull/36

Timestamp: 2025-03-06T20:42:41.590Z
Learning: In the y-scope/ystdlib-cpp project, the linting scope is limited to .h, .hpp, and .cpp files, and the header-only detection logic in CMake checks for .h, .hpp, and .inc extensions.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: Bill-hbrhbr
PR: y-scope/ystdlib-cpp#32
File: CMakeLists.txt:0-0
Timestamp: 2025-02-28T05:04:33.616Z
Learning: The y-scope/ystdlib-cpp project uses the "YSTDLIB_CPP_" prefix for project-specific CMake variables, following good naming convention practices.

Comment on lines 44 to 45
DEPENDS
INTERNAL_DEPENDS
Copy link
Member

Choose a reason for hiding this comment

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

Lets match the cmake naming so something like:
PUBLIC_LINK_LIBS (and PRIVATE...) or just PUBLIC_LIBS maybe.

Copy link
Collaborator Author

@Bill-hbrhbr Bill-hbrhbr Mar 10, 2025

Choose a reason for hiding this comment

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

I've renamed everything to use very explicit names. I got the idea of INTERFACE_LIBRARIES from here (which is CMake official doc)

Comment on lines 42 to 43
HEADERS
SOURCES
Copy link
Member

Choose a reason for hiding this comment

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

I think everything works even if we don't separate/distinguish headers and source files, so I think just SOURCES is fine. If it is important to separate them, then maybe we should concatenate them and pass both to check_if_header_only_library to avoid user error (currently if you put a cpp file in HEADERS I think things will break)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Not important to separate now, but will make a difference when we only want to install public headers into install library paths.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

On a second thought, I've decided to keep them split and renamed the params for more clarity. I've also enforced a check of the public header list.

@Bill-hbrhbr Bill-hbrhbr requested a review from davidlion March 10, 2025 09:19
@Bill-hbrhbr
Copy link
Collaborator Author

TLDR of changes since last review (except for the ones directly resolving your comments):

  1. Renamed param names of cpp_library() and made them more verbose for more clarity.
  2. Added a check to enforce header-only files in INTERFACE_HEADERS by making a small update to the helper function
  3. Added a variable that stores the alias target name and updated all reference sites.

@davidlion davidlion changed the title build(cmake): Add support for library targets with source files and linked libraries. build(cmake): Add support for building library targets that contain source files and linked libraries. Mar 12, 2025
@Bill-hbrhbr Bill-hbrhbr requested a review from davidlion March 14, 2025 04:48
@Bill-hbrhbr Bill-hbrhbr requested a review from davidlion March 16, 2025 23:18
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