cmake: add a helper for linking into static libs #1678

pull theuni wants to merge 1 commits into bitcoin-core:master from theuni:static-helper-lib changing 1 files +10 −1
  1. theuni commented at 6:33 pm on June 3, 2025: contributor

    As discussed here: #1674 (comment)

    Parent projects (Bitcoin Core in this case) may wish to include secp256k1 in another static library (libbitcoinkernel) so that users are not forced to bring their own static libsecp256k1.

    Unfortunately, CMake lacks the machinery to link (combine) one static lib into another.

    To work around this, secp256k1_objs is exposed as an interface library which parent projects can “link” into static libs.

  2. theuni commented at 6:34 pm on June 3, 2025: contributor
    For reference, here’s a branch demonstrating Core’s usage of it for the kernel: https://github.com/theuni/bitcoin/commits/static_kernel/
  3. real-or-random added the label build on Jun 3, 2025
  4. real-or-random commented at 6:40 pm on June 3, 2025: contributor

    Obvious Concept ACK if Bitcoin Core needs this

    But what’s the status on the Core side of things? Has it been decided yet that kernel will use this? If not, we may want to wait. If Core doesn’t need it, I’m not sure if we should include this feature. It’s rather niche, and a bit of a layer violation.

  5. theuni commented at 6:44 pm on June 3, 2025: contributor

    A few notes:

    • Object libraries are frustrating and don’t propagate dependencies as one would hope.
    • Linking against $<TARGET_OBJECTS:foo> doesn’t actually pull the objects into static libs, hence their inclusion as interface sources.
    • secp256k1_asm_arm is used directly rather than secp256k1_asm as otherwise the public asm/field_10x26_arm.s bubbles up to Core and requires us to enable the ASM language.
    • One/some/all of the binaries could be switched to use secp256k1_objs as a test. As an added benefit, that would avoid runtime path issues when building as a shared lib.
  6. theuni commented at 6:47 pm on June 3, 2025: contributor

    Obvious Concept ACK if Bitcoin Core needs this

    But what’s the status on the Core side of things? Has it been decided yet that kernel will use this? If not, we may want to wait. If Core doesn’t need it, I’m not sure if we should include this feature. It’s rather niche, and a bit of a layer violation.

    This came up as a real-world frustration during last week’s working group call.

    Ping @TheCharlatan @stickies-v @fanquake @hebasto for their thoughts.

  7. theuni commented at 6:49 pm on June 3, 2025: contributor

    It’s rather niche, and a bit of a layer violation.

    Btw, I agree that this is a layer violation of sorts, but it’s intended to avoid a worse one in Core. The alternative is for us to specify secp’s internals at that layer: https://github.com/theuni/bitcoin/commit/4f43838247fa62b8495133b3924ebb64f08dd0ec

  8. real-or-random added the label feature on Jun 3, 2025
  9. hebasto commented at 10:02 pm on June 3, 2025: member

    Ping … @hebasto for their thoughts.

    Looking for possible alternatives.

  10. hebasto commented at 8:54 am on June 4, 2025: member

    Concept ACK.

    I would not consider this approach a layer violation. An INTERFACE library is used to provide the interface, including include directories, between a subproject and its parent project when the latter integrates the former within the same build system, as is the case with libsecp256k1 and Bitcoin Core.

    However, some explanatory documentation or comments would be useful.

  11. hebasto commented at 8:58 am on June 4, 2025: member

    A few notes:

    • Object libraries are frustrating and don’t propagate dependencies as one would hope.

    They do. But this is effective only at the linking stage, which is not the case for a “combined” static library.

  12. hebasto commented at 9:14 am on June 4, 2025: member
    • secp256k1_asm_arm is used directly rather than secp256k1_asm as otherwise the public asm/field_10x26_arm.s bubbles up to Core and requires us to enable the ASM language.

    I believe this explanation may not be accurate. To my knowledge, CMake does not allow INTERFACE libraries, such as secp256k1_asm, in $<TARGET_OBJECTS:...> generator expressions.

  13. in src/CMakeLists.txt:15 in e2ff2e5617 outdated
     9@@ -10,13 +10,19 @@ add_library(secp256k1_precomputed OBJECT EXCLUDE_FROM_ALL
    10 # from being exported.
    11 add_library(secp256k1 secp256k1.c $<TARGET_OBJECTS:secp256k1_precomputed>)
    12 
    13+# Create a helper lib that parent projects can use to link secp256k1 into a
    14+# static lib.
    15+add_library(secp256k1_objs INTERFACE EXCLUDE_FROM_ALL)
    


    hebasto commented at 10:18 am on June 4, 2025:

    This command fails with CMake 3.16:

    0CMake Error at src/CMakeLists.txt:15 (add_library):
    1  add_library INTERFACE library may not be used with EXCLUDE_FROM_ALL.
    

    This signature has been added in CMake 3.19.

    Rebase on top of #1675?


    hebasto commented at 10:28 am on June 4, 2025:
    Because the SOURCES property of the secp256k1_objs target is not set, it is not an actual build target, so the EXCLUDE_FROM_ALL option may be omitted.

    real-or-random commented at 10:30 am on June 4, 2025:

    Rebase on top of #1675?

    just merged that one

  14. hebasto commented at 10:35 am on June 4, 2025: member

    Also some duplication might be avoided:

     0--- a/src/CMakeLists.txt
     1+++ b/src/CMakeLists.txt
     2@@ -37,16 +37,17 @@ endif()
     3 get_target_property(use_pic secp256k1 POSITION_INDEPENDENT_CODE)
     4 set_target_properties(secp256k1_precomputed PROPERTIES POSITION_INDEPENDENT_CODE ${use_pic})
     5 
     6-target_include_directories(secp256k1 INTERFACE
     7-  # Add the include path for parent projects so that they don't have to manually add it.
     8+set(_include_directory_for_parent_projects
     9   $<BUILD_INTERFACE:$<$<NOT:$<BOOL:${PROJECT_IS_TOP_LEVEL}>>:${PROJECT_SOURCE_DIR}/include>>
    10+)
    11+target_include_directories(secp256k1 INTERFACE
    12+  ${_include_directory_for_parent_projects}
    13   $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
    14 )
    15-
    16 target_include_directories(secp256k1_objs INTERFACE
    17-  # Add the include path for parent projects so that they don't have to manually add it.
    18-  $<BUILD_INTERFACE:$<$<NOT:$<BOOL:${PROJECT_IS_TOP_LEVEL}>>:${PROJECT_SOURCE_DIR}/include>>
    19+  ${_include_directory_for_parent_projects}
    20 )
    21+unset(_include_directory_for_parent_projects)
    22 
    23 # This emulates Libtool to make sure Libtool and CMake agree on the ABI version,
    24 # see below "Calculate the version variables" in build-aux/ltmain.sh.
    
  15. theuni commented at 4:01 pm on June 4, 2025: contributor
    • secp256k1_asm_arm is used directly rather than secp256k1_asm as otherwise the public asm/field_10x26_arm.s bubbles up to Core and requires us to enable the ASM language.

    I believe this explanation may not be accurate. To my knowledge, CMake does not allow INTERFACE libraries, such as secp256k1_asm, in $<TARGET_OBJECTS:...> generator expressions.

    Yes, in this case I meant that linking secp256k1_asm into secp256k1_objs caused this problem. Otherwise that approach would’ve bee preferred.

  16. theuni commented at 4:08 pm on June 4, 2025: contributor

    Also some duplication might be avoided:

    Nice. Also, after #1679 this could just be:

    0set_target_properties(secp256k1_objs PROPERTIES $<TARGET_PROPERTY:secp256k1, INTERFACE_INCLUDE_DIRECTORIES>)
    
  17. stickies-v commented at 4:07 pm on June 5, 2025: none

    Parent projects (Bitcoin Core in this case) may wish to include secp256k1 in another static library (libbitcoinkernel) so that users are not forced to bring their own static libsecp256k1.

    Concept ACK, this would be very helpful for py-bitcoinkernel. I’m in the process of porting the library to use the kernel C++ header, whereby I have to link against a static bitcoinkernel. Not having to also link to kernel’s dependencies makes that process a lot more elegant, as tested with a patch very similar to https://github.com/theuni/bitcoin/commit/bc2aea3251602eb8f79356a63109573e5c37ea90.

  18. theuni force-pushed on Jun 5, 2025
  19. theuni commented at 5:16 pm on June 5, 2025: contributor
    Addressed @hebasto’s feedback.
  20. theuni force-pushed on Jun 5, 2025
  21. theuni commented at 5:56 pm on June 5, 2025: contributor
    Rebased.
  22. hebasto approved
  23. hebasto commented at 7:52 pm on June 5, 2025: member
    ACK 51d2ecd6e9f8ec1048d04fae34c2430c749d3bff. Tested using this branch by linking the executable against both the shared and static versions of the bitcoinkernel library.
  24. hebasto commented at 10:29 am on June 16, 2025: member

    Also some duplication might be avoided:

    Nice. Also, after #1679 this could just be:

    0set_target_properties(secp256k1_objs PROPERTIES $<TARGET_PROPERTY:secp256k1, INTERFACE_INCLUDE_DIRECTORIES>)
    

    #1679 has just been merged.

  25. hebasto commented at 3:08 pm on June 16, 2025: member

    @real-or-random

    Maybe add this PR to the 0.7.0 milestone?

  26. real-or-random commented at 3:11 pm on June 16, 2025: contributor

    Maybe add this PR to the 0.7.0 milestone?

    Okay, makes sense given that Bitcoin Core will need it. Added.

  27. real-or-random added this to the milestone 0.7.0 on Jun 16, 2025
  28. cmake: add a helper for linking into static libs
    Parent projects (Bitcoin Core in this case) may wish to include secp256k1
    in another static library (libbitcoinkernel) so that users are not forced
    to bring their own static libsecp256k1.
    
    Unfortunately, CMake lacks the machinery to link (combine) one static lib
    into another.
    
    To work around this, secp256k1_objs is exposed as an interface library which
    parent projects can "link" into static libs..
    145ae3e28d
  29. theuni force-pushed on Jun 16, 2025
  30. theuni commented at 5:12 pm on June 16, 2025: contributor

    Rebased and updated.

    A (non-rebased) version of this can be seen/tested here: https://github.com/theuni/bitcoin/commits/static_kernel/

    Building Core with BUILD_KERNEL_LIB=ON and BUILD_SHARED_LIBS=OFF shows the secp objs getting linked in correctly.

  31. real-or-random requested review from hebasto on Jun 17, 2025
  32. in src/CMakeLists.txt:89 in 145ae3e28d
    85 target_include_directories(secp256k1 INTERFACE
    86-  # Add the include path for parent projects so that they don't have to manually add it.
    87   $<BUILD_INTERFACE:$<$<NOT:$<BOOL:${PROJECT_IS_TOP_LEVEL}>>:${PROJECT_SOURCE_DIR}/include>>
    88 )
    89+set_target_properties(secp256k1_objs PROPERTIES
    90+    INTERFACE_INCLUDE_DIRECTORIES "$<TARGET_PROPERTY:secp256k1,INTERFACE_INCLUDE_DIRECTORIES>"
    


    hebasto commented at 7:58 am on June 17, 2025:
    This generator expression has a behaviour change in version 3.26, but it doesn’t affect us.
  33. hebasto approved
  34. hebasto commented at 7:59 am on June 17, 2025: member

    ACK 145ae3e28d587dd04866ec5893be9270bc99289a, tested on Ubuntu 24.04 using cmake 3.22.6 and the default cmake 3.28.3.

    Because the SOURCES property of the secp256k1_objs target is not set, it is not an actual build target…

    Perhaps it would be clearer if this target were named secp256k1_interface_objs or something similar?

  35. theuni commented at 5:57 pm on June 17, 2025: contributor

    @hebasto Mmm, I’m not sure that’s any clearer. I also considered secp256k1_objs_interface, but that would lead one to believe that it has no sources/objects.

    I think I’d prefer to leave it as-is unless you feel strongly.

  36. hebasto commented at 10:25 am on June 18, 2025: member

    Mmm, I’m not sure that’s any clearer. I also considered secp256k1_objs_interface, but that would lead one to believe that it has no sources/objects.

    That’s technically correct. The SOURCE property of the new target is empty.

    Additionally, from a downstream project developer’s perspective, take Bitcoin Core as an example:

     0add_library(bitcoinkernel
     1  bitcoinkernel.cpp
     2  ...
     3  $<TARGET_OBJECTS:bitcoin_clientversion>
     4  $<TARGET_OBJECTS:bitcoin_crypto>
     5  $<TARGET_OBJECTS:leveldb>
     6  $<TARGET_OBJECTS:crc32c>
     7)
     8target_link_libraries(bitcoinkernel
     9  PRIVATE
    10    core_interface
    11    secp256k1_objs
    12    $<$<PLATFORM_ID:Windows>:bcrypt>
    13    $<TARGET_NAME_IF_EXISTS:USDT::headers>
    14  PUBLIC
    15    Boost::headers
    16)
    

    You can build all bitcoinkernel prerequisites except core_interface:

    0$ cmake --build build -t bitcoin_clientversion bitcoin_crypto leveldb crc32c
    1$ cmake --build build -t core_interface
    2ninja: error: unknown target 'core_interface'
    

    The new library clearly belongs to that latter group:

    0$ cmake --build build -t secp256k1_objs
    1ninja: error: unknown target 'secp256k1_objs'
    

    I think I’d prefer to leave it as-is unless you feel strongly.

    I don’t consider my comment to be a blocker.

  37. hebasto commented at 10:32 am on June 18, 2025: member
  38. stickies-v approved
  39. stickies-v commented at 1:26 pm on June 18, 2025: none

    Light ACK 145ae3e28d587dd04866ec5893be9270bc99289a

    I tested (macOS 15.4, cmake 4.0.2) by subtree-ing this branch into https://github.com/TheCharlatan/bitcoin/tree/kernelApi_Cpp_Internal_Headers and cherry-picking https://github.com/theuni/bitcoin/commit/23c5503640a7e2073b7573e725b4d3a296a3bb08 on top of it. Statically linking against this monolith works fine for me.

    Light ACK because I only have superficial cmake knowledge and almost no knowledge of the secp256k1 repo. I just wanted to test if this works for my use case, and it does.

  40. theuni commented at 2:41 pm on June 18, 2025: contributor
    @hebasto I don’t disagree with any of the above, I just don’t think it fits with the _interface suffix as we use it (mostly flags and dependency resolution), since linking against this lib does bring in objects, even if they’re not listed in TARGET_OBJECTS.
  41. real-or-random merged this on Jun 24, 2025
  42. real-or-random closed this on Jun 24, 2025

  43. real-or-random added the label needs-changelog on Jun 24, 2025
  44. real-or-random commented at 9:43 am on June 24, 2025: contributor
    Given that this is a feature, I wonder if this should get a changelog entry. I’ve added the label for now. But I don’t feel competent enough in CMake to write one. @theuni Can you give it a try?

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin-core/secp256k1. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2025-06-28 23:15 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me