From 60c6bd8c3807107b84060975c6216452f097c23b Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Wed, 2 Jul 2025 11:43:32 +0200 Subject: [PATCH 1/3] build: Refactor visibility logic --- include/secp256k1.h | 71 ++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 39 deletions(-) diff --git a/include/secp256k1.h b/include/secp256k1.h index 1d25a02ab2..6066b5debf 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -121,45 +121,38 @@ typedef int (*secp256k1_nonce_function)( #endif /* Symbol visibility. */ -#if defined(_WIN32) - /* GCC for Windows (e.g., MinGW) accepts the __declspec syntax - * for MSVC compatibility. A __declspec declaration implies (but is not - * exactly equivalent to) __attribute__ ((visibility("default"))), and so we - * actually want __declspec even on GCC, see "Microsoft Windows Function - * Attributes" in the GCC manual and the recommendations in - * https://gcc.gnu.org/wiki/Visibility. */ -# if defined(SECP256K1_BUILD) -# if defined(DLL_EXPORT) || defined(SECP256K1_DLL_EXPORT) - /* Building libsecp256k1 as a DLL. - * 1. If using Libtool, it defines DLL_EXPORT automatically. - * 2. In other cases, SECP256K1_DLL_EXPORT must be defined. */ -# define SECP256K1_API extern __declspec (dllexport) -# else - /* Building libsecp256k1 as a static library on Windows. - * No declspec is needed, and so we would want the non-Windows-specific - * logic below take care of this case. However, this may result in setting - * __attribute__ ((visibility("default"))), which is supposed to be a noop - * on Windows but may trigger warnings when compiling with -flto due to a - * bug in GCC, see - * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116478 . */ -# define SECP256K1_API extern -# endif - /* The user must define SECP256K1_STATIC when consuming libsecp256k1 as a static - * library on Windows. */ -# elif !defined(SECP256K1_STATIC) - /* Consuming libsecp256k1 as a DLL. */ -# define SECP256K1_API extern __declspec (dllimport) -# endif -#endif -#ifndef SECP256K1_API -/* All cases not captured by the Windows-specific logic. */ -# if defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD) - /* Building libsecp256k1 using GCC or compatible. */ -# define SECP256K1_API extern __attribute__ ((visibility ("default"))) -# else - /* Fall back to standard C's extern. */ -# define SECP256K1_API extern -# endif +#if !defined(SECP256K1_API) +# if defined(SECP256K1_BUILD) + /* On Windows, assume a shared library only if explicitly requested. + * 1. If using Libtool, it defines DLL_EXPORT automatically. + * 2. In other cases, SECP256K1_DLL_EXPORT must be defined. */ +# if defined(_WIN32) && defined(SECP256K1_DLL_EXPORT) || defined(DLL_EXPORT) + /* GCC for Windows (e.g., MinGW) accepts the __declspec syntax for + * MSVC compatibility. A __declspec declaration implies (but is not + * exactly equivalent to) __attribute__ ((visibility("default"))), + * and so we actually want __declspec even on GCC, see "Microsoft + * Windows Function Attributes" in the GCC manual and the + * recommendations in https://gcc.gnu.org/wiki/Visibility . */ +# define SECP256K1_API extern __declspec(dllexport) + /* Avoid __attribute__ ((visibility("default"))) on Windows to get rid + * of warnings when compiling with -flto due to a bug in GCC, see + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116478 . */ +# elif defined (__GNUC__) && (__GNUC__ >= 4) && !defined(_WIN32) +# define SECP256K1_API extern __attribute__ ((visibility("default"))) +# else +# define SECP256K1_API extern +# endif +# else + /* On Windows, SECP256K1_STATIC must be defined when consuming + * libsecp256k1 as a static library. Note that SECP256K1_STATIC is a + * "consumer-only" macro, and it has no meaning when building + * libsecp256k1. */ +# if defined(_WIN32) && !defined(SECP256K1_STATIC) +# define SECP256K1_API extern __declspec(dllimport) +# else +# define SECP256K1_API extern +# endif +# endif #endif /* Warning attributes From 57b520d40ff305fde549b040cfe05e9fd9d8d0c2 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Wed, 2 Jul 2025 11:56:40 +0200 Subject: [PATCH 2/3] build: Add SECP256K1_NO_VISIBILITY_ATTRIBUTES --- include/secp256k1.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/secp256k1.h b/include/secp256k1.h index 6066b5debf..6a49d2c9e0 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -121,6 +121,25 @@ typedef int (*secp256k1_nonce_function)( #endif /* Symbol visibility. */ +#if !defined(SECP256K1_API) && defined(SECP256K1_NO_API_VISIBILITY_ATTRIBUTES) + /* The user has requested that we don't specify visibility attributes in + * the public API. + * + * Since all our non-API declarations use the static qualifier, this means + * that the user can use -fvisibility= to set the visibility of the + * API symbols. For instance, -fvisibility=hidden can be useful *even for + * the API symbols*, e.g., when building a static library which is linked + * into a shared library, and the latter should not re-export the + * libsecp256k1 API. + * + * While visibility is a concept that applies only to shared libraries, + * setting visibility will still make a difference when building a static + * library: the visibility settings will be stored in the static library, + * solely for the potential case that the static library will be linked into + * a shared library. In that case, the stored visibility settings will + * resurface and be honored for the shared library. */ +# define SECP256K1_API extern +#endif #if !defined(SECP256K1_API) # if defined(SECP256K1_BUILD) /* On Windows, assume a shared library only if explicitly requested. From 203376ceba642392557644e27dcb67abaf9e58de Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 2 Jul 2025 15:18:06 +0000 Subject: [PATCH 3/3] build: add CMake option for disabling symbol visibility attributes Co-authored-by: Tim Ruffing --- CMakeLists.txt | 3 +++ src/CMakeLists.txt | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 26cc49b157..5b4148f001 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,8 @@ endif() option(SECP256K1_INSTALL "Enable installation." ${PROJECT_IS_TOP_LEVEL}) +option(SECP256K1_ENABLE_API_VISIBILITY_ATTRIBUTES "Enable visibility attributes in the API." ON) + ## Modules # We declare all options before processing them, to make sure we can express @@ -312,6 +314,7 @@ else() set(cross_status "FALSE") endif() message("Cross compiling ....................... ${cross_status}") +message("Visibility attributes ................. ${SECP256K1_ENABLE_VISIBILITY_ATTRIBUTES}") message("Valgrind .............................. ${SECP256K1_VALGRIND}") get_directory_property(definitions COMPILE_DEFINITIONS) string(REPLACE ";" " " definitions "${definitions}") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8f1d2ee3ba..7060ef3f28 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -54,6 +54,10 @@ add_library(secp256k1_precomputed OBJECT EXCLUDE_FROM_ALL # from being exported. target_sources(secp256k1 PRIVATE secp256k1.c $) +if(NOT SECP256K1_ENABLE_VISIBILITY_ATTRIBUTES) + target_compile_definitions(secp256k1 PRIVATE SECP256K1_NO_VISIBILITY_ATTRIBUTES) +endif() + # Create a helper lib that parent projects can use to link secp256k1 into a # static lib. add_library(secp256k1_objs INTERFACE)