Fix CXX interface exports and headers

Added separate export header, export macros for all required classes and functions and installing the headers in the correct directory structure.
This commit is contained in:
Kai Blaschke
2025-12-06 19:35:04 +01:00
parent db22c9335a
commit b33eed393d
17 changed files with 195 additions and 60 deletions

View File

@ -199,16 +199,6 @@ else()
endif()
endif()
if(ENABLE_CXX_INTERFACE)
set(CMAKE_C_VISIBILITY_PRESET default)
set(CMAKE_CXX_VISIBILITY_PRESET default)
set(CMAKE_VISIBILITY_INLINES_HIDDEN OFF)
else()
set(CMAKE_C_VISIBILITY_PRESET hidden)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
endif()
# Disable trace/debug logging in release builds unless explicitly requested
add_compile_definitions(
$<$<OR:$<CONFIG:Debug>,$<BOOL:${ENABLE_VERBOSE_LOGGING}>>:ENABLE_DEBUG_LOGGING>

View File

@ -11,6 +11,14 @@ generate_export_header(projectM_api
EXPORT_FILE_NAME "${PROJECTM_EXPORT_HEADER}"
)
# Always generate the header, but we only install it if the C++ interface is actually enabled.
set(PROJECTM_CXX_EXPORT_HEADER "${CMAKE_CURRENT_BINARY_DIR}/include/projectM-4/projectM_cxx_export.h")
generate_export_header(projectM_api
BASE_NAME projectM_CXX
EXPORT_FILE_NAME "${PROJECTM_CXX_EXPORT_HEADER}"
)
set(PROJECTM_PUBLIC_HEADERS
"${PROJECTM_EXPORT_HEADER}"
"${CMAKE_CURRENT_BINARY_DIR}/include/projectM-4/version.h"
@ -28,6 +36,10 @@ set(PROJECTM_PUBLIC_HEADERS
include/projectM-4/user_sprites.h
)
if(ENABLE_CXX_INTERFACE)
list(APPEND PROJECTM_PUBLIC_HEADERS ${PROJECTM_CXX_EXPORT_HEADER})
endif()
target_sources(projectM_api
PRIVATE
${PROJECTM_PUBLIC_HEADERS}
@ -46,6 +58,14 @@ target_include_directories(projectM_api
"$<INSTALL_INTERFACE:${PROJECTM_INCLUDE_DIR}>"
)
if(NOT BUILD_SHARED_LIBS)
target_compile_definitions(projectM_api
INTERFACE
PROJECTM_STATIC_DEFINE
PROJECTM_CXX_STATIC_DEFINE
)
endif()
add_library(libprojectM::API ALIAS projectM_api)

View File

@ -20,4 +20,18 @@ target_include_directories(Audio
target_link_libraries(Audio
PUBLIC
libprojectM::API
)
)
if(BUILD_SHARED_LIBS)
if(ENABLE_CXX_INTERFACE)
target_compile_definitions(Audio
PRIVATE
projectM_api_EXPORTS
)
else()
target_compile_definitions(Audio
PRIVATE
PROJECTM_CXX_STATIC_DEFINE
)
endif()
endif()

View File

@ -8,14 +8,14 @@
#include "Audio/AudioConstants.hpp"
#include <projectM-4/projectM_export.h>
#include <projectM-4/projectM_cxx_export.h>
#include <array>
namespace libprojectM {
namespace Audio {
class PROJECTM_EXPORT FrameAudioData
class PROJECTM_CXX_EXPORT FrameAudioData
{
public:
float bass{0.f};

View File

@ -7,6 +7,8 @@
#include "Audio/AudioConstants.hpp"
#include <projectM-4/projectM_cxx_export.h>
#include <array>
#include <cstdint>
@ -16,14 +18,14 @@ namespace Audio {
/**
* @brief Calculates beat-detection loudness relative to the previous frame(s).
*/
class Loudness
class PROJECTM_CXX_EXPORT Loudness
{
public:
/**
* @brief Frequency bands.
* Only the first half of the spectrum is used for these bands, each using one third of this half.
*/
enum class Band : int
enum class Band : std::uint8_t
{
Bass = 0, //!< Bass band (first sixth of the spectrum)
Middles = 1, //!< Middles band (second sixth of the spectrum)
@ -76,7 +78,7 @@ private:
void UpdateBandAverage(double secondsSinceLastFrame, uint32_t frame);
/**
* @brief Adjusts the dampening rate according the the current FPS.
* @brief Adjusts the dampening rate according to the current FPS.
* @param rate The rate to be dampened.
* @param secondsSinceLastFrame (Fractional) seconds passed since the last frame.
* @return The dampened rate value.

View File

@ -29,7 +29,10 @@ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include <projectM-4/projectM_cxx_export.h>
#include <complex>
#include <cstddef>
#include <vector>
namespace libprojectM {
@ -40,7 +43,7 @@ namespace Audio {
* Also applies an equalizer pattern with an envelope curve to the resulting data to smooth out
* certain artifacts.
*/
class MilkdropFFT
class PROJECTM_CXX_EXPORT MilkdropFFT
{
public:
/**

View File

@ -13,7 +13,7 @@
#include "Audio/MilkdropFFT.hpp"
#include "Audio/WaveformAligner.hpp"
#include <projectM-4/projectM_export.h>
#include <projectM-4/projectM_cxx_export.h>
#include <atomic>
#include <cstdint>
@ -23,7 +23,7 @@
namespace libprojectM {
namespace Audio {
class PCM
class PROJECTM_CXX_EXPORT PCM
{
public:
/**
@ -33,7 +33,7 @@ public:
* @param channels The number of channels in the input data.
* @param count The amount of samples in the buffer
*/
PROJECTM_EXPORT void Add(const float* samples, uint32_t channels, size_t count);
void Add(const float* samples, uint32_t channels, size_t count);
/**
* @brief Adds new mono unsigned 8-bit PCM data to the storage
@ -42,7 +42,7 @@ public:
* @param channels The number of channels in the input data.
* @param count The amount of samples in the buffer
*/
PROJECTM_EXPORT void Add(const uint8_t* samples, uint32_t channels, size_t count);
void Add(const uint8_t* samples, uint32_t channels, size_t count);
/**
* @brief Adds new mono signed 16-bit PCM data to the storage
@ -51,7 +51,7 @@ public:
* @param channels The number of channels in the input data.
* @param count The amount of samples in the buffer
*/
PROJECTM_EXPORT void Add(const int16_t* samples, uint32_t channels, size_t count);
void Add(const int16_t* samples, uint32_t channels, size_t count);
/**
* @brief Updates the internal audio data values for rendering the next frame.
@ -64,13 +64,13 @@ public:
* @param secondsSinceLastFrame Time passed since rendering the last frame. Basically 1.0/FPS.
* @param frame Frames rendered since projectM was started.
*/
PROJECTM_EXPORT void UpdateFrameAudioData(double secondsSinceLastFrame, uint32_t frame);
void UpdateFrameAudioData(double secondsSinceLastFrame, uint32_t frame);
/**
* @brief Returns a class holding a copy of the current frame audio data.
* @return A FrameAudioData class with waveform, spectrum and other derived values.
*/
PROJECTM_EXPORT auto GetFrameAudioData() const -> FrameAudioData;
auto GetFrameAudioData() const -> FrameAudioData;
private:
template<

View File

@ -7,7 +7,9 @@
#include "Audio/AudioConstants.hpp"
#include <cstddef>
#include <projectM-4/projectM_cxx_export.h>
#include <array>
#include <cstdint>
#include <vector>
@ -23,7 +25,7 @@ namespace Audio {
* This will keep similar features in-place instead of randomly jumping around on each frame and creates
* for a smoother-looking waveform visualization.
*/
class WaveformAligner
class PROJECTM_CXX_EXPORT WaveformAligner
{
public:
WaveformAligner();
@ -36,7 +38,7 @@ public:
protected:
void GenerateWeights();
int CalculateOffset(std::vector<WaveformBuffer>& newWaveformMips);
auto CalculateOffset(std::vector<WaveformBuffer>& newWaveformMips) -> int;
void ResampleOctaves(std::vector<WaveformBuffer>& dstWaveformMips, WaveformBuffer& newWaveform);
bool m_alignWaveReady{false}; //!< Alignment needs special treatment for the first buffer fill.

View File

@ -77,6 +77,13 @@ target_include_directories(projectM
"$<INSTALL_INTERFACE:${PROJECTM_INCLUDE_DIR}>"
)
if(ENABLE_CXX_INTERFACE)
target_include_directories(projectM
PUBLIC
"$<INSTALL_INTERFACE:${PROJECTM_INCLUDE_DIR}/projectM-4>"
)
endif()
target_link_libraries(projectM
PUBLIC
${PROJECTM_OPENGL_LIBRARIES}
@ -99,10 +106,25 @@ set_target_properties(projectM PROPERTIES
)
if(BUILD_SHARED_LIBS)
target_compile_definitions(projectM_main
PRIVATE
projectM_api_EXPORTS
)
# If the C++ interface was requested, enable all exports. Otherwise,
# we only enable API exports for the C wrapper, and disable it for all other files.
if(ENABLE_CXX_INTERFACE)
target_compile_definitions(projectM_main
PRIVATE
projectM_api_EXPORTS
)
else()
# Using PROJECTM_CXX_STATIC_DEFINE has precedence over projectM_api_EXPORTS,
# so all PROJECTM_CXX_EXPORT macros are removed.
target_compile_definitions(projectM_main
PRIVATE
PROJECTM_CXX_STATIC_DEFINE
)
set_source_files_properties(ProjectMCWrapper.cpp PROPERTIES
COMPILE_DEFINITIONS projectM_api_EXPORTS
)
endif()
target_link_libraries(projectM
PUBLIC
@ -112,6 +134,13 @@ else()
target_compile_definitions(projectM_main
PUBLIC
PROJECTM_STATIC_DEFINE
PROJECTM_CXX_STATIC_DEFINE
)
target_compile_definitions(projectM
INTERFACE
PROJECTM_STATIC_DEFINE
PROJECTM_CXX_STATIC_DEFINE
)
set_target_properties(projectM PROPERTIES
@ -134,24 +163,30 @@ if(ENABLE_INSTALL)
if(ENABLE_CXX_INTERFACE)
install(FILES
Audio/AudioConstants.hpp
Audio/FrameAudioData.hpp
Audio/Loudness.hpp
Audio/MilkdropFFT.hpp
Audio/PCM.hpp
Audio/WaveformAligner.hpp
DESTINATION "${PROJECTM_INCLUDE_DIR}/projectM-4/Audio"
COMPONENT Devel
)
install(FILES
Renderer/RenderContext.hpp
DESTINATION "${PROJECTM_INCLUDE_DIR}/projectM-4/Renderer"
COMPONENT Devel
)
install(FILES
Logging.hpp
ProjectM.hpp
DESTINATION "${PROJECTM_INCLUDE_DIR}/projectM-4"
COMPONENT Devel
)
else()
# Set PROJECTM_STATIC_EXPORT for C++ implementations to use project default visibility
# and no dllimport/dllexport.
set_source_files_properties(ProjectM.cpp Audio/PCM.cpp PROPERTIES
COMPILE_DEFINITIONS PROJECTM_STATIC_DEFINE
)
target_compile_definitions(projectM
INTERFACE
PROJECTM_STATIC_DEFINE
)
endif()
# CMake target exports
# For use from a local projectM build tree (without installing)

View File

@ -1,5 +1,7 @@
#pragma once
#include <projectM-4/projectM_cxx_export.h>
#include <cstdint>
#include <string>
@ -48,38 +50,38 @@ public:
* Sets the global callback function pointer used across all threads.
* @param callback A UserCallback struct with the new function and user data pointers.
*/
static void SetGlobalCallback(UserCallback callback);
PROJECTM_CXX_EXPORT static void SetGlobalCallback(UserCallback callback);
/**
* Sets the thread-specific callback function pointer only used in the thread which registered it.
* @param callback A UserCallback struct with the new function and user data pointers.
*/
static void SetThreadCallback(UserCallback callback);
PROJECTM_CXX_EXPORT static void SetThreadCallback(UserCallback callback);
/**
* Sets the global log level used across all threads.
* @param logLevel The log level to use. If set to LogLevel::NotSet, the value of m_defaultLogLevel is used.
*/
static void SetGlobalLogLevel(LogLevel logLevel);
PROJECTM_CXX_EXPORT static void SetGlobalLogLevel(LogLevel logLevel);
/**
* Sets the thread-specific log level only used in the thread which set it.
* @param logLevel The log level to use. If set to LogLevel::NotSet, the value of m_defaultLogLevel is used.
*/
static void SetThreadLogLevel(LogLevel logLevel);
PROJECTM_CXX_EXPORT static void SetThreadLogLevel(LogLevel logLevel);
/**
* Returns the effective log level for the current thread.
* @return The log level set for this thread, or, if LogLevel::NotSet, the global log level.
* If no global log level is set, it returns the value of m_defaultLogLevel.
*/
static auto GetLogLevel() -> LogLevel;
PROJECTM_CXX_EXPORT static auto GetLogLevel() -> LogLevel;
/**
* Returns whether a callback is registered or not.
* @return true if a callback is registered for the current thread or globally, false if none is registered.
*/
static auto HasCallback() -> bool;
PROJECTM_CXX_EXPORT static auto HasCallback() -> bool;
/**
* @brief Passes a log message with the given severity to the active thread or global callback.
@ -87,12 +89,12 @@ public:
* @param message
* @param severity
*/
static void Log(const std::string& message, LogLevel severity);
PROJECTM_CXX_EXPORT static void Log(const std::string& message, LogLevel severity);
/**
* The default log level used if no log level is set (LogLevel::Information)
*/
static const LogLevel m_defaultLogLevel;
PROJECTM_CXX_EXPORT static const LogLevel m_defaultLogLevel;
private:
/**

View File

@ -143,11 +143,24 @@ target_link_libraries(MilkdropPreset
${PROJECTM_OPENGL_LIBRARIES}
)
if(NOT BUILD_SHARED_LIBS)
if(BUILD_SHARED_LIBS)
if(ENABLE_CXX_INTERFACE)
target_compile_definitions(MilkdropPreset
PRIVATE
projectM_api_EXPORTS
)
else()
target_compile_definitions(MilkdropPreset
PRIVATE
PROJECTM_CXX_STATIC_DEFINE
)
endif()
else()
target_compile_definitions(MilkdropPreset
PRIVATE
PROJECTM_STATIC_DEFINE
)
PRIVATE
PROJECTM_STATIC_DEFINE
PROJECTM_CXX_STATIC_DEFINE
)
endif()
set_target_properties(MilkdropPreset PROPERTIES

View File

@ -20,12 +20,14 @@
*/
#pragma once
#include <projectM-4/projectM_export.h>
#include <projectM-4/projectM_cxx_export.h>
#include <Renderer/RenderContext.hpp>
#include <Audio/PCM.hpp>
#include <cstdint>
#include <istream>
#include <memory>
#include <string>
#include <vector>
@ -49,11 +51,16 @@ class Preset;
class PresetFactoryManager;
class TimeKeeper;
class PROJECTM_EXPORT ProjectM
class PROJECTM_CXX_EXPORT ProjectM
{
public:
ProjectM();
ProjectM(const ProjectM& other) = delete;
ProjectM(ProjectM&& other) noexcept = delete;
auto operator=(const ProjectM& other) -> ProjectM& = delete;
auto operator=(ProjectM&& other) noexcept -> ProjectM& = delete;
virtual ~ProjectM();
/**
@ -122,7 +129,7 @@ public:
* system clock will be returned.
* @return Seconds elapsed rendering the last frame since starting projectM.
*/
double GetFrameTime();
auto GetFrameTime() -> double;
void SetBeatSensitivity(float sensitivity);

View File

@ -39,7 +39,7 @@ libprojectM::projectMWrapper* handle_to_instance(projectm_handle instance)
return reinterpret_cast<libprojectM::projectMWrapper*>(instance);
}
char* projectm_alloc_string(unsigned int length)
PROJECTM_EXPORT char* projectm_alloc_string(unsigned int length)
{
try
{
@ -51,7 +51,7 @@ char* projectm_alloc_string(unsigned int length)
}
}
char* projectm_alloc_string_from_std_string(const std::string& str)
PROJECTM_EXPORT char* projectm_alloc_string_from_std_string(const std::string& str)
{
auto pointer = projectm_alloc_string(static_cast<uint32_t>(str.length() + 1));
if (pointer)

View File

@ -81,3 +81,23 @@ target_link_libraries(Renderer
set_target_properties(Renderer PROPERTIES
FOLDER libprojectM
)
if(BUILD_SHARED_LIBS)
if(ENABLE_CXX_INTERFACE)
target_compile_definitions(Renderer
PRIVATE
projectM_api_EXPORTS
)
else()
target_compile_definitions(Renderer
PRIVATE
PROJECTM_CXX_STATIC_DEFINE
)
endif()
else()
target_compile_definitions(Renderer
PRIVATE
PROJECTM_STATIC_DEFINE
PROJECTM_CXX_STATIC_DEFINE
)
endif()

View File

@ -4,6 +4,8 @@
*/
#pragma once
#include <projectM-4/projectM_cxx_export.h>
namespace libprojectM {
namespace Renderer {
@ -13,7 +15,7 @@ class TextureManager;
/**
* @brief Holds all global data of the current rendering context, which can change from frame to frame.
*/
class RenderContext
class PROJECTM_CXX_EXPORT RenderContext
{
public:
float time{0.0f}; //!< Time since the preset started, in seconds.

View File

@ -37,3 +37,23 @@ target_link_libraries(UserSprites
GLM::GLM
${PROJECTM_OPENGL_LIBRARIES}
)
if(BUILD_SHARED_LIBS)
if(ENABLE_CXX_INTERFACE)
target_compile_definitions(UserSprites
PRIVATE
projectM_api_EXPORTS
)
else()
target_compile_definitions(UserSprites
PRIVATE
PROJECTM_CXX_STATIC_DEFINE
)
endif()
else()
target_compile_definitions(UserSprites
PRIVATE
PROJECTM_STATIC_DEFINE
PROJECTM_CXX_STATIC_DEFINE
)
endif()

View File

@ -13,6 +13,11 @@ add_library(hlslparser OBJECT
src/HLSLTree.h
)
target_link_libraries(hlslparser
PRIVATE
projectM_api # For projectM_cxx_export.h, required by Logging.hpp
)
target_include_directories(hlslparser
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src