diff --git a/CMakeLists.txt b/CMakeLists.txt index c5d96fc35..0a52ab06b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,10 @@ set(PROJECTM_BIN_DIR "bin" CACHE STRING "Executable installation directory, rela set(PROJECTM_LIB_DIR "lib" CACHE STRING "Library installation directory, relative to the install prefix.") set(PROJECTM_INCLUDE_DIR "include" CACHE STRING "Header installation directory, relative to the install prefix.") +# Dummy file for merged static libs. +set(PROJECTM_DUMMY_SOURCE_FILE "${CMAKE_BINARY_DIR}/dummy.cpp") +file(TOUCH "${PROJECTM_DUMMY_SOURCE_FILE}") + if(CMAKE_SYSTEM_NAME STREQUAL Emscripten) set(ENABLE_EMSCRIPTEN ON CACHE BOOL "Build for web with emscripten. Will also build the SDL2-based entrypoint." FORCE) else() @@ -42,9 +46,7 @@ else() endif() # Feature options, including dependencies. -option(ENABLE_STATIC_LIB "Build and install libprojectM as a static library" ON) -cmake_dependent_option(ENABLE_SHARED_LIB "Build and install libprojectM as a shared library" ON "NOT ENABLE_EMSCRIPTEN" OFF) -cmake_dependent_option(ENABLE_SHARED_LINKING "Link the SDL test UI against the shared library." ON "ENABLE_SHARED_LIB" OFF) +cmake_dependent_option(BUILD_SHARED_LIBS "Build and install libprojectM as a shared libraries. If OFF, builds as static libraries." ON "NOT ENABLE_EMSCRIPTEN" OFF) option(ENABLE_DOXYGEN "Build and install Doxygen source code documentation in PROJECTM_DATADIR_PATH/docs." OFF) option(ENABLE_CXX_INTERFACE "Enable exporting all C++ symbols, not only the C API, in the shared library. Warning: This is not very portable." OFF) option(ENABLE_PRESETS "Build and install bundled presets" ON) @@ -57,10 +59,6 @@ cmake_dependent_option(ENABLE_LLVM "Enable LLVM JIT support" OFF "NOT ENABLE_EMS option(ENABLE_SYSTEM_GLM "Enable use of system-install GLM library" OFF) option(ENABLE_PLAYLIST "Enable building the playlist management library" ON) -if(NOT ENABLE_STATIC_LIB AND NOT ENABLE_SHARED_LIB) - message(FATAL_ERROR "At least one of either ENABLE_STATIC_LIB or ENABLE_SHARED_LIB options must be set to ON.") -endif() - if(ENABLE_DOXYGEN) find_package(Doxygen REQUIRED) endif() @@ -210,6 +208,7 @@ message(STATUS "") message(STATUS "Features:") message(STATUS "==============================================") message(STATUS "") +message(STATUS " Build shared libraries: ${BUILD_SHARED_LIBS}") message(STATUS " Presets: ${ENABLE_PRESETS}") message(STATUS " Threading: ${ENABLE_THREADING}") message(STATUS " SDL2: ${ENABLE_SDL_UI}") @@ -232,8 +231,7 @@ message(STATUS "") message(STATUS "Targets and applications:") message(STATUS "==============================================") message(STATUS "") -message(STATUS " libprojectM static: ${ENABLE_STATIC_LIB}") -message(STATUS " libprojectM shared: ${ENABLE_SHARED_LIB}") +message(STATUS " libprojectM: (always built)") message(STATUS " Playlist library: ${ENABLE_PLAYLIST}") message(STATUS " SDL2 Test UI: ${ENABLE_SDL_UI}") message(STATUS " Doxygen API docs: ${ENABLE_DOXYGEN}") diff --git a/src/api/CMakeLists.txt b/src/api/CMakeLists.txt index 225e8faa8..8097f3116 100644 --- a/src/api/CMakeLists.txt +++ b/src/api/CMakeLists.txt @@ -27,7 +27,7 @@ generate_export_header(projectM_api EXPORT_FILE_NAME "${PROJECTM_EXPORT_HEADER}" ) -add_library(projectM::API ALIAS projectM_api) +add_library(libprojectM::API ALIAS projectM_api) install(TARGETS projectM_api diff --git a/src/libprojectM/CMakeLists.txt b/src/libprojectM/CMakeLists.txt index d5aec4dc7..05de71388 100644 --- a/src/libprojectM/CMakeLists.txt +++ b/src/libprojectM/CMakeLists.txt @@ -17,7 +17,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows") STBI_NO_DDS projectM_FONT_MENU="${CMAKE_SOURCE_DIR}/fonts/VeraMono.ttf" projectM_FONT_TITLE="${CMAKE_SOURCE_DIR}/fonts/Vera.ttf" - ) + ) endif() # List of targets used in export(). @@ -32,16 +32,9 @@ set(EXPORTED_TARGETS add_subdirectory(MilkdropPresetFactory) add_subdirectory(Renderer) -# CMake cannot combine multiple static libraries using target_link_libraries. -# This syntax will pull in the compiled object files into the final library. add_library(projectM_main OBJECT "${PROJECTM_EXPORT_HEADER}" Common.hpp - fatal.h - fftsg.cpp - fftsg.h - glError.h - gltext.h HungarianMethod.hpp IdleTextures.hpp PCM.cpp @@ -55,17 +48,31 @@ add_library(projectM_main OBJECT PresetFactoryManager.hpp ProjectM.cpp ProjectM.hpp - projectM-opengl.h + ProjectMCWrapper.cpp + ProjectMCWrapper.hpp RandomNumberGenerators.hpp - resource.h - TestRunner.cpp - TestRunner.hpp TimeKeeper.cpp TimeKeeper.hpp + fatal.h + fftsg.cpp + fftsg.h + glError.h + gltext.h + projectM-opengl.h + resource.h wipemalloc.cpp wipemalloc.h ) +target_link_libraries(projectM_main + PUBLIC + MilkdropPresetFactory + Renderer + hlslparser + SOIL2 + libprojectM::API + ) + target_include_directories(projectM_main PRIVATE "${CMAKE_SOURCE_DIR}/src" @@ -76,29 +83,80 @@ target_include_directories(projectM_main "${MSVC_EXTRA_INCLUDE_DIR}" ) -target_link_libraries(projectM_main - PRIVATE - GLM::GLM - PUBLIC - ${PROJECTM_OPENGL_LIBRARIES} - PUBLIC - projectM::API +# CMake cannot combine multiple static libraries using target_link_libraries. +# This syntax will pull in the compiled object files into the final library. +add_library(projectM + ${PROJECTM_DUMMY_SOURCE_FILE} # CMake needs at least one "real" source file. + $ + $ + $ + $ + $ ) -if (ENABLE_STATIC_LIB) - include(libprojectM_static.cmake) +target_include_directories(projectM + PUBLIC + "$" + ) + +target_link_libraries(projectM + PUBLIC + ${PROJECTM_OPENGL_LIBRARIES} + libprojectM::API + ) + +if(ENABLE_LLVM) + target_link_libraries(projectM + PUBLIC + LLVM::LLVM + ) endif() -if(ENABLE_SHARED_LIB) - include(libprojectM_shared.cmake) +if(ENABLE_OPENMP) + target_link_libraries(projectM + PUBLIC + OpenMP::OpenMP_CXX + ) endif() -if(ENABLE_SHARED_LINKING) - add_library(projectM::libprojectM ALIAS projectM_shared) +set_target_properties(projectM PROPERTIES + VERSION "${PROJECTM_LIB_VERSION}" + SOVERSION "${PROJECTM_SO_VERSION}" + FOLDER libprojectM + ) + +if(BUILD_SHARED_LIBS) + target_compile_definitions(projectM + PRIVATE + projectM_api_EXPORTS + ) + + target_link_libraries(projectM + PUBLIC + ${CMAKE_DL_LIBS} + ) else() - add_library(projectM::libprojectM ALIAS projectM_static) + target_compile_definitions(projectM + PUBLIC + PROJECTM_STATIC_DEFINE + ) + + set_target_properties(projectM PROPERTIES + OUTPUT_NAME $,libprojectM,projectM> + FOLDER libprojectM + ) endif() +add_library(libprojectM::projectM ALIAS projectM) + +install(TARGETS projectM + EXPORT libprojectMTargets + LIBRARY DESTINATION "${PROJECTM_LIB_DIR}" + RUNTIME DESTINATION "${PROJECTM_LIB_DIR}" + ARCHIVE DESTINATION "${PROJECTM_LIB_DIR}" + COMPONENT Runtime + ) + if(ENABLE_CXX_INTERFACE) install(FILES Common.hpp @@ -116,7 +174,7 @@ endif() # For use from a local projectM build tree (without installing) export(TARGETS projectM_api - ${EXPORTED_TARGETS} + projectM NAMESPACE libprojectM:: FILE projectM-exports.cmake ) @@ -152,6 +210,15 @@ if(NOT ENABLE_EMSCRIPTEN AND ENABLE_GLES) ) endif() +if(ENABLE_LLVM) + install(FILES + "${CMAKE_SOURCE_DIR}/cmake/gles/FindLLVM.cmake" + DESTINATION "${PROJECTM_LIB_DIR}/cmake/libprojectM" + COMPONENT Devel + ) +endif() + + install(EXPORT libprojectMTargets FILE libprojectMTargets.cmake NAMESPACE libprojectM:: @@ -159,3 +226,24 @@ install(EXPORT libprojectMTargets COMPONENT Devel ) +# pkg-config export, only supports static library on UNIX systems. +if(UNIX AND NOT BUILD_SHARED_LIBS) + macro(set_pkg_config_path varname path) + if(IS_ABSOLUTE "${path}") + set(${varname} "${path}") + else() + set(${varname} "\${prefix}/${path}") + endif() + endmacro() + + set(PKGCONFIG_PREFIX "${CMAKE_INSTALL_PREFIX}") + set_pkg_config_path(PKGCONFIG_LIB_DIR "${PROJECTM_LIB_DIR}") + set_pkg_config_path(PKGCONFIG_INCLUDE_DIR "${PROJECTM_INCLUDE_DIR}") + set_pkg_config_path(PKGCONFIG_DATADIR_PATH "${PROJECTM_DATADIR_PATH}") + + configure_file(libprojectM.pc.cmake.in "${CMAKE_BINARY_DIR}/libprojectM.pc" @ONLY) + install(FILES "${CMAKE_BINARY_DIR}/libprojectM.pc" + DESTINATION "${PROJECTM_LIB_DIR}/pkgconfig" + COMPONENT Devel + ) +endif() diff --git a/src/libprojectM/MilkdropPresetFactory/Expr.cpp b/src/libprojectM/MilkdropPresetFactory/Expr.cpp index 2bdd35b93..07224f78d 100755 --- a/src/libprojectM/MilkdropPresetFactory/Expr.cpp +++ b/src/libprojectM/MilkdropPresetFactory/Expr.cpp @@ -1048,195 +1048,6 @@ Expr *Expr::create_program_expr(std::vector &steps_, bool ownSteps) } - - -// TESTS - -#include - -#ifndef NDEBUG - -#define TEST(cond) if (!verify(#cond,cond)) return false - - -struct ExprTest : public Test -{ - bool eq(float a, float b) - { - return std::abs(a-b) < (std::abs(a)+std::abs(b) + 1)/1000.0f; - } - - Expr *constant(float f) - { - return Expr::const_to_expr(3.0f); - } - - ExprTest() : Test("ExprTest") - {} - -public: - bool optimize_constant_expr() - { - BuiltinFuncs::init_builtin_func_db(); - Func *sin_fn = BuiltinFuncs::find_func("sin"); - Func *rand_fn = BuiltinFuncs::find_func("rand"); - - TreeExpr *a = TreeExpr::create(nullptr, Expr::const_to_expr( 1.0 ), nullptr, nullptr); - TreeExpr *b = TreeExpr::create(nullptr, Expr::const_to_expr( 2.0 ), nullptr, nullptr); - Expr *c = TreeExpr::create(Eval::infix_add, nullptr, a, b); - Expr *x = Expr::optimize(c); - TEST(x != c); - c = nullptr; - TEST(x->clazz == CONSTANT); - TEST(3.0f == x->eval(-1,-1)); - Expr::delete_expr(x); - - Expr **expr_array = (Expr **)malloc(sizeof(Expr *)); - expr_array[0] = TreeExpr::create(nullptr, Expr::const_to_expr( (float)M_PI ), nullptr, nullptr); - Expr *sin = Expr::prefun_to_expr(sin_fn, expr_array); - x = Expr::optimize(sin); - TEST(x != sin); - sin = nullptr; - TEST(x->clazz == CONSTANT); - TEST(sinf( (float)M_PI ) == x->eval(-1,-10)); - Expr::delete_expr(x); - - // make sure rand() is not optimized away - expr_array = (Expr **)malloc(sizeof(Expr *)); - expr_array[0] = TreeExpr::create(nullptr, Expr::const_to_expr( (float)M_PI ), nullptr, nullptr); - Expr *rand = Expr::prefun_to_expr(rand_fn, expr_array); - x = Expr::optimize(rand); - TEST(x == rand); - rand = nullptr; - TEST(x->clazz != CONSTANT); - Expr::delete_expr(x); - - return true; - } - -#if HAVE_LLVM - bool jit() - { - Func *if_fn = BuiltinFuncs::find_func("if"); - Func *sin_fn = BuiltinFuncs::find_func("sin"); - Func *rand_fn = BuiltinFuncs::find_func("rand"); - - { - Expr *CONST = Expr::const_to_expr(3.0f); - Expr *jitExpr = Expr::jit(CONST); - TEST(3.0f == jitExpr->eval(-1,-1)); - delete jitExpr; // jitExpr now owns CONST, TODO make behavior consistent with optimize() - } - - { - Param *PARAM = Param::createUser("test"); - PARAM->set_param(4.0f); - Expr *jitExpr = Expr::jit(PARAM); - TEST(4.0f == jitExpr->eval(-1,-1)); - delete jitExpr; - } - - { - Expr *CONST = Expr::const_to_expr(3.0f); - Param *PARAM = Param::createUser("test"); - PARAM->set_param(4.0f); - Expr *MULT = new TreeExprMult(CONST, PARAM); - Expr *jitExpr = Expr::jit(MULT); - TEST(12.0f == jitExpr->eval(-1,-1)); - delete jitExpr; - } - - { - Expr *CONST = Expr::const_to_expr(3.0f); - Param *PARAM = Param::createUser("test"); - PARAM->set_param(4.0f); - Expr *ASSIGN = new AssignMatrixExpr(PARAM, CONST); - Expr *jitExpr = Expr::jit(ASSIGN); - TEST(3.0f == jitExpr->eval(-1,-1)); - TEST(3.0f == PARAM->eval(-1,-1)); - delete jitExpr; - } - - { - Expr *CONST = Expr::const_to_expr(3.0f); - Expr **expr_list = (Expr **)malloc(1 * sizeof(Expr *)); - SinExpr *SIN = new SinExpr(sin_fn, expr_list); - SIN->num_args = 1; - SIN->func_ptr = FuncWrappers::sin_wrapper; - SIN->expr_list = (Expr **)malloc(1 * sizeof(Expr *)); - SIN->expr_list[0] = CONST; - Expr *jitExpr = Expr::jit(SIN); - TEST(sinf(3.0f) == jitExpr->eval(-1,-1)); - delete jitExpr; - } - - // test_prefun_if: - { - Expr *CONST1 = Expr::const_to_expr(1.0f); - Expr *CONST2 = Expr::const_to_expr(2.0f); - Expr *CONST3 = Expr::const_to_expr(3.0f); - Expr **expr_list = (Expr **)malloc(3 * sizeof(Expr *)); - expr_list[0] = CONST1; - expr_list[1] = CONST2; - expr_list[2] = CONST3; - PrefunExpr *IF = new IfExpr(if_fn, expr_list); // TODO constructor - Expr *jitExpr = Expr::jit(IF); - TEST(2.0f == jitExpr->eval(-1,-1)); - delete jitExpr; - } - - //test_ternary_mod_1: - { - Expr *CONST2 = Expr::const_to_expr(2.0f); - Expr *CONST3 = Expr::const_to_expr(3.0f); - TreeExpr *MOD = TreeExpr::create(Eval::infix_mod, CONST3, CONST2); - Expr *jitExpr = Expr::jit(MOD); - TEST(1.0f == jitExpr->eval(-1,-1)); - delete jitExpr; - } - - //test_ternary_mod_2: - { - Expr *CONST0 = Expr::const_to_expr(0.0f); - Expr *CONST3 = Expr::const_to_expr(3.0f); - TreeExpr *MOD = TreeExpr::create(Eval::infix_mod, CONST3, CONST0); - Expr *jitExpr = Expr::jit(MOD); - TEST(0.0f == jitExpr->eval(-1,-1)); - delete jitExpr; - } - - return true; - } -#endif - - bool test() override - { - Eval::init_infix_ops(); - bool result = true; - result &= optimize_constant_expr(); -#if HAVE_LLVM - result &= jit(); -#endif - return result; - } -}; - -Test* Expr::test() -{ - return new ExprTest(); -} - -#else - -Test* Expr::test() -{ - return nullptr; -} - -#endif - - - #if HAVE_LLVM using namespace llvm; diff --git a/src/libprojectM/MilkdropPresetFactory/Param.cpp b/src/libprojectM/MilkdropPresetFactory/Param.cpp index 2c798c6e1..6df211742 100755 --- a/src/libprojectM/MilkdropPresetFactory/Param.cpp +++ b/src/libprojectM/MilkdropPresetFactory/Param.cpp @@ -392,37 +392,3 @@ Param * Param::createUser( const std::string &name ) { return new _FloatParam( name ); } - - -// TESTS - - -#include - -#ifndef NDEBUG - -struct ParamTest : public Test -{ - ParamTest() : Test("ParamTest") - {} - -public: - bool test() override - { - return true; - } -}; - -Test* Param::test() -{ - return new ParamTest(); -} - -#else - -Test* Param::test() -{ - return nullptr; -} - -#endif diff --git a/src/libprojectM/TestRunner.cpp b/src/libprojectM/TestRunner.cpp deleted file mode 100644 index d9fbd147e..000000000 --- a/src/libprojectM/TestRunner.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// -// Created by matthew on 1/7/19. -// - -#include -#include -#include - -std::vector TestRunner::tests; - - -bool Test::verify(const char *test, bool success) -{ - if (!success) - std::cout << "failed " << test << std::endl; - return success; -} - - -bool TestRunner::run() -{ - if (tests.empty()) - { - // We still call register/run tests in NDEBUG (useful for performance testing) - // but tests may choose to comment out body to save space - tests.push_back(Param::test()); - tests.push_back(Expr::test()); - } - - int count = 0; - bool successful = true; - for (auto it=tests.begin() ; it < tests.end() ; it++ ) - { - if (nullptr == (*it)) - continue; - count++; - std::cout << "TestRunner: " << (*it)->getName() << " started" << std::endl; - std::cout.flush(); - bool result = (*it)->test(); - successful &= result; - if (result) - std::cout << "TestRunner: " << (*it)->getName() << " passed" << std::endl; - else - std::cout << "TestRunner: " << (*it)->getName() << " FAILED" << std::endl; - } - if (0 == count) - std::cout << "TestRunner: no tests found to run" << std::endl; - return successful; -} diff --git a/src/libprojectM/TestRunner.hpp b/src/libprojectM/TestRunner.hpp deleted file mode 100644 index 53678dff0..000000000 --- a/src/libprojectM/TestRunner.hpp +++ /dev/null @@ -1,43 +0,0 @@ -// -// Created by matthew on 1/7/19. -// -// This is a place to collect/run non-graphical unit tests -// CONSIDER using some framework like googletest etc, but for now didn't want new dependencies -// - -#ifndef PROJECTM_LUA_TESTRUNNER_H -#define PROJECTM_LUA_TESTRUNNER_H - - -#include -#include - - -class Test -{ -public: - const std::string getName() { return name; }; -#ifdef NDEBUG - virtual bool test() {return true;} -#else - virtual bool test() = 0; -#endif - virtual ~Test() = default; -protected: - explicit Test(std::string name_) : name(name_) {}; - const std::string name; - - bool verify(const char *test, bool success); -}; - - -class TestRunner -{ -public: - static bool run(); -private: - static std::vector tests; -}; - - -#endif //PROJECTM_LUA_TESTRUNNER_H diff --git a/src/libprojectM/libprojectMConfig.cmake.in b/src/libprojectM/libprojectMConfig.cmake.in index d5b7903bc..5b97e945f 100644 --- a/src/libprojectM/libprojectMConfig.cmake.in +++ b/src/libprojectM/libprojectMConfig.cmake.in @@ -12,14 +12,18 @@ if(NOT "@ENABLE_EMSCRIPTEN@") # ENABLE_EMSCRIPTEN find_dependency(OpenGL) endif() endif() +if("@ENABLE_LLVM@") # ENABLE_LLVM + list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") + find_dependency(LLVM) +endif() if("@ENABLE_OPENMP@") # ENABLE_OPENMP - find_dependency(OpenMP) + find_dependency(OpenMP) endif() if("@ENABLE_THREADING@") # ENABLE_THREADING - find_dependency(Threads) + find_dependency(Threads) endif() if(CMAKE_SYSTEM_NAME STREQUAL "Windows") - find_dependency(GLEW) + find_dependency(GLEW) endif() set(_libprojectM_FIND_PARTS_REQUIRED) diff --git a/src/libprojectM/libprojectM_shared.cmake b/src/libprojectM/libprojectM_shared.cmake deleted file mode 100644 index aa75ea59c..000000000 --- a/src/libprojectM/libprojectM_shared.cmake +++ /dev/null @@ -1,77 +0,0 @@ -add_library(projectM_shared SHARED - ProjectMCWrapper.cpp - ProjectMCWrapper.hpp - $ - $ - $ - $ - $ - ) - -target_compile_definitions(projectM_shared - PRIVATE - projectM_main_EXPORTS - ) - -set_target_properties(projectM_shared PROPERTIES - OUTPUT_NAME projectM - VERSION "${PROJECTM_LIB_VERSION}" - SOVERSION "${PROJECTM_SO_VERSION}" - EXPORT_NAME shared - FOLDER libprojectM - ) - -target_include_directories(projectM_shared - PUBLIC - "$" - ) - -target_link_libraries(projectM_shared - PUBLIC - projectM::API - ${PROJECTM_OPENGL_LIBRARIES} - ${CMAKE_DL_LIBS} - ) - -if(ENABLE_OPENMP) - target_link_libraries(projectM_shared - PUBLIC - OpenMP::OpenMP_CXX - ) -endif() - -if(ENABLE_THREADING) - target_link_libraries(projectM_shared - PUBLIC - Threads::Threads - ) -endif() - -if(ENABLE_LLVM) - target_link_libraries(projectM_shared - PUBLIC - LLVM::LLVM - ) -endif() - -if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - target_link_libraries(projectM_shared - PUBLIC - "-framework CoreFoundation" - ) -endif() - -# --no-undefined doesn't make sense for Windows as all symbols are always required to be defined -if (NOT WIN32) - enable_target_linker_flags_if_supported(projectM_shared PRIVATE --no-undefined) -endif() - -install(TARGETS projectM_shared - EXPORT libprojectMTargets - LIBRARY DESTINATION "${PROJECTM_LIB_DIR}" - RUNTIME DESTINATION "${PROJECTM_LIB_DIR}" - ARCHIVE DESTINATION "${PROJECTM_LIB_DIR}" - COMPONENT Runtime - ) - -list(APPEND EXPORTED_TARGETS projectM_shared) diff --git a/src/libprojectM/libprojectM_static.cmake b/src/libprojectM/libprojectM_static.cmake deleted file mode 100644 index 860bf6049..000000000 --- a/src/libprojectM/libprojectM_static.cmake +++ /dev/null @@ -1,92 +0,0 @@ -add_library(projectM_static STATIC - ProjectMCWrapper.cpp - ProjectMCWrapper.hpp - $ - $ - $ - $ - $ - ) - -target_compile_definitions(projectM_static - PUBLIC - PROJECTM_STATIC_DEFINE - ) - -set_target_properties(projectM_static PROPERTIES - OUTPUT_NAME $,libprojectM,projectM> - EXPORT_NAME static - FOLDER libprojectM - ) - -target_include_directories(projectM_static - PUBLIC - "$" - ) - -target_link_libraries(projectM_static - PUBLIC - projectM::API - ${PROJECTM_OPENGL_LIBRARIES} - ) - -if(ENABLE_OPENMP) - target_link_libraries(projectM_static - PUBLIC - OpenMP::OpenMP_CXX - ) -endif() - -if(ENABLE_THREADING) - target_link_libraries(projectM_static - PUBLIC - Threads::Threads - ) -endif() - -if(ENABLE_LLVM) - target_link_libraries(projectM_static - PUBLIC - LLVM::LLVM - ) -endif() - -if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - target_link_libraries(projectM_static - PUBLIC - "-framework CoreFoundation" - ) -endif() - -install(TARGETS projectM_static - EXPORT libprojectMTargets - LIBRARY DESTINATION "${PROJECTM_LIB_DIR}" - RUNTIME DESTINATION "${PROJECTM_LIB_DIR}" - ARCHIVE DESTINATION "${PROJECTM_LIB_DIR}" - COMPONENT Runtime - ) - -list(APPEND EXPORTED_TARGETS projectM_static) - - -# pkg-config export, only supports static library on UNIX systems. -if(UNIX) - macro(set_pkg_config_path varname path) - if(IS_ABSOLUTE "${path}") - set(${varname} "${path}") - else() - set(${varname} "\${prefix}/${path}") - endif() - endmacro() - - set(PKGCONFIG_PREFIX "${CMAKE_INSTALL_PREFIX}") - set_pkg_config_path(PKGCONFIG_LIB_DIR "${PROJECTM_LIB_DIR}") - set_pkg_config_path(PKGCONFIG_INCLUDE_DIR "${PROJECTM_INCLUDE_DIR}") - set_pkg_config_path(PKGCONFIG_DATADIR_PATH "${PROJECTM_DATADIR_PATH}") - - configure_file(libprojectM.pc.cmake.in "${CMAKE_BINARY_DIR}/libprojectM.pc" @ONLY) - install(FILES "${CMAKE_BINARY_DIR}/libprojectM.pc" - DESTINATION "${PROJECTM_LIB_DIR}/pkgconfig" - COMPONENT Devel - ) -endif() diff --git a/src/playlist/CMakeLists.txt b/src/playlist/CMakeLists.txt index 4dfe82bb7..3c45aaf1d 100644 --- a/src/playlist/CMakeLists.txt +++ b/src/playlist/CMakeLists.txt @@ -2,7 +2,7 @@ if(NOT ENABLE_PLAYLIST) return() endif() -add_library(projectM_playlist STATIC +add_library(projectM_playlist_main OBJECT Filter.cpp Filter.hpp Item.cpp @@ -14,25 +14,76 @@ add_library(projectM_playlist STATIC playlist.h ) +target_include_directories(projectM_playlist_main + PUBLIC + ${CMAKE_CURRENT_BINARY_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR} + ) + +target_link_libraries(projectM_playlist_main + PUBLIC + libprojectM::projectM + ) + +add_library(projectM_playlist + ${PROJECTM_DUMMY_SOURCE_FILE} # CMake needs at least one "real" source file. + $ + ) + +set_target_properties(projectM_playlist PROPERTIES + VERSION "${PROJECTM_LIB_VERSION}" + SOVERSION "${PROJECTM_SO_VERSION}" + EXPORT_NAME playlist + FOLDER libprojectM + ) + target_include_directories(projectM_playlist PUBLIC $ + $ + "$" ) target_link_libraries(projectM_playlist PUBLIC - projectM::API + libprojectM::projectM ) -set_target_properties(projectM_playlist PROPERTIES - EXPORT_NAME playlist - FOLDER libprojectM +if(BUILD_SHARED_LIBS) + target_compile_definitions(projectM_playlist + PRIVATE + projectM_api_EXPORTS + ) + + target_link_libraries(projectM_playlist + PUBLIC + ${CMAKE_DL_LIBS} + ) +else() + target_compile_definitions(projectM_playlist + PUBLIC + PROJECTM_STATIC_DEFINE + ) + + set_target_properties(projectM_playlist PROPERTIES + OUTPUT_NAME $,libprojectM_playlist,projectM_playlist> + FOLDER libprojectM + ) +endif() + +include(GenerateExportHeader) + +set(PROJECTM_PLAYLIST_EXPORT_HEADER "${CMAKE_CURRENT_BINARY_DIR}/include/libprojectM/projectM_playlist_export.h") + +generate_export_header(projectM_playlist + BASE_NAME projectM_playlist + EXPORT_FILE_NAME "${PROJECTM_PLAYLIST_EXPORT_HEADER}" ) # Adds fallback support to boost if std::filesystem is unavailable. include(FilesystemSupport.cmake) -add_library(projectM::playlist ALIAS projectM_playlist) +add_library(libprojectM::playlist ALIAS projectM_playlist) install(TARGETS projectM_playlist EXPORT libprojectMPlaylist @@ -44,6 +95,7 @@ install(TARGETS projectM_playlist install(FILES playlist.h + "${CMAKE_CURRENT_BINARY_DIR}/include/libprojectM/projectM_playlist_export.h" DESTINATION "${PROJECTM_INCLUDE_DIR}/libprojectM" COMPONENT Devel ) diff --git a/src/playlist/FilesystemSupport.cmake b/src/playlist/FilesystemSupport.cmake index 377105390..48e580566 100644 --- a/src/playlist/FilesystemSupport.cmake +++ b/src/playlist/FilesystemSupport.cmake @@ -18,11 +18,11 @@ set(CMAKE_CXX_STANDARD 14) if(NOT ENABLE_BOOST_FILESYSTEM AND STD_FILESYSTEM_EXISTS) message(STATUS "Building playlist library using C++17 and std::filesystem.") - set_target_properties(projectM_playlist PROPERTIES + set_target_properties(projectM_playlist_main PROPERTIES CXX_STANDARD 17 ) - target_compile_definitions(projectM_playlist + target_compile_definitions(projectM_playlist_main PRIVATE FS_NAMESPACE=std FS_INCLUDE= @@ -31,12 +31,17 @@ else() message(STATUS "Compiler does not support std::filesystem, reverting to boost::filesystem.") find_package(Boost REQUIRED COMPONENTS Filesystem) - target_compile_definitions(projectM_playlist + target_compile_definitions(projectM_playlist_main PRIVATE FS_NAMESPACE=boost FS_INCLUDE= ) + target_link_libraries(projectM_playlist_main + PUBLIC + Boost::filesystem + ) + target_link_libraries(projectM_playlist PUBLIC Boost::filesystem diff --git a/src/playlist/playlist.h b/src/playlist/playlist.h index b13fe07e1..975ffa7e4 100644 --- a/src/playlist/playlist.h +++ b/src/playlist/playlist.h @@ -1,6 +1,7 @@ #pragma once #include "libprojectM/projectM.h" +#include "libprojectM/projectM_playlist_export.h" #ifdef __cplusplus extern "C" { @@ -37,7 +38,7 @@ typedef enum * * @param string A pointer to a string that should be freed. */ -void projectm_playlist_free_string(char* string); +PROJECTM_PLAYLIST_EXPORT void projectm_playlist_free_string(char* string); /** * @brief Frees a string array returned by any of the playlist API functions. @@ -47,7 +48,7 @@ void projectm_playlist_free_string(char* string); * * @param array The pointer to the array of strings that should be freed. */ -void projectm_playlist_free_string_array(char** array); +PROJECTM_PLAYLIST_EXPORT void projectm_playlist_free_string_array(char** array); /** * @brief Callback function that is executed on each preset change. @@ -96,7 +97,7 @@ typedef void (*projectm_playlist_preset_switch_failed_event)(const char* preset_ * created playlist instance unconnected. * @return An opaque pointer to the newly created playlist manager instance. Null if creation failed. */ -projectm_playlist_handle projectm_playlist_create(projectm_handle projectm_instance); +PROJECTM_PLAYLIST_EXPORT projectm_playlist_handle projectm_playlist_create(projectm_handle projectm_instance); /** * @brief Destroys a previously created playlist manager. @@ -105,7 +106,7 @@ projectm_playlist_handle projectm_playlist_create(projectm_handle projectm_insta * * @param instance The playlist manager instance to destroy. */ -void projectm_playlist_destroy(projectm_playlist_handle instance); +PROJECTM_PLAYLIST_EXPORT void projectm_playlist_destroy(projectm_playlist_handle instance); /** * @brief Sets a callback function that will be called when a preset changes. @@ -117,7 +118,7 @@ void projectm_playlist_destroy(projectm_playlist_handle instance); * @param user_data A pointer to any data that will be sent back in the callback, e.g. context * information. */ -void projectm_playlist_set_preset_switched_event_callback(projectm_playlist_handle instance, +PROJECTM_PLAYLIST_EXPORT void projectm_playlist_set_preset_switched_event_callback(projectm_playlist_handle instance, projectm_playlist_preset_switched_event callback, void* user_data); @@ -136,7 +137,7 @@ void projectm_playlist_set_preset_switched_event_callback(projectm_playlist_hand * @param user_data A pointer to any data that will be sent back in the callback, e.g. context * information. */ -void projectm_playlist_set_preset_switch_failed_event_callback(projectm_playlist_handle instance, +PROJECTM_PLAYLIST_EXPORT void projectm_playlist_set_preset_switch_failed_event_callback(projectm_playlist_handle instance, projectm_playlist_preset_switch_failed_event callback, void* user_data); @@ -156,20 +157,20 @@ void projectm_playlist_set_preset_switch_failed_event_callback(projectm_playlist * @param projectm_instance The projectM instance to connect to. Can be a null pointer to remove * an existing binding and clear the projectM preset switch callback. */ -void projectm_playlist_connect(projectm_playlist_handle instance, projectm_handle projectm_instance); +PROJECTM_PLAYLIST_EXPORT void projectm_playlist_connect(projectm_playlist_handle instance, projectm_handle projectm_instance); /** * @brief Returns the number of presets in the current playlist. * @param instance The playlist manager instance. * @return The number of presets in the current playlist. */ -uint32_t projectm_playlist_size(projectm_playlist_handle instance); +PROJECTM_PLAYLIST_EXPORT uint32_t projectm_playlist_size(projectm_playlist_handle instance); /** * @brief Clears the playlist. * @param instance The playlist manager instance to clear. */ -void projectm_playlist_clear(projectm_playlist_handle instance); +PROJECTM_PLAYLIST_EXPORT void projectm_playlist_clear(projectm_playlist_handle instance); /** * @brief Returns a list of preset files inside the given range of the current playlist, in order. @@ -188,7 +189,7 @@ void projectm_playlist_clear(projectm_playlist_handle instance); * @return A pointer to a list of char pointers, each containing a single preset. The last entry * is denoted by a null pointer. */ -char** projectm_playlist_items(projectm_playlist_handle instance, uint32_t start, uint32_t count); +PROJECTM_PLAYLIST_EXPORT char** projectm_playlist_items(projectm_playlist_handle instance, uint32_t start, uint32_t count); /** * @brief Returns the name of a preset at the given index in the current playlist. @@ -200,7 +201,7 @@ char** projectm_playlist_items(projectm_playlist_handle instance, uint32_t start * @return The filename of the requested preset, or NULL if the index was out of bounds or the * playlist is empty. */ -char* projectm_playlist_item(projectm_playlist_handle instance, uint32_t index); +PROJECTM_PLAYLIST_EXPORT char* projectm_playlist_item(projectm_playlist_handle instance, uint32_t index); /** * @brief Appends presets from the given path to the end of the current playlist. @@ -218,7 +219,7 @@ char* projectm_playlist_item(projectm_playlist_handle instance, uint32_t index); * added that do not already exist in the current playlist. * @return The number of files added. 0 may indicate issues scanning the path. */ -uint32_t projectm_playlist_add_path(projectm_playlist_handle instance, const char* path, +PROJECTM_PLAYLIST_EXPORT uint32_t projectm_playlist_add_path(projectm_playlist_handle instance, const char* path, bool recurse_subdirs, bool allow_duplicates); @@ -240,7 +241,7 @@ uint32_t projectm_playlist_add_path(projectm_playlist_handle instance, const cha * added that do not already exist in the current playlist. * @return The number of files added. 0 may indicate issues scanning the path. */ -uint32_t projectm_playlist_insert_path(projectm_playlist_handle instance, const char* path, +PROJECTM_PLAYLIST_EXPORT uint32_t projectm_playlist_insert_path(projectm_playlist_handle instance, const char* path, uint32_t index, bool recurse_subdirs, bool allow_duplicates); /** @@ -256,7 +257,7 @@ uint32_t projectm_playlist_insert_path(projectm_playlist_handle instance, const * @return True if the file was added to the playlist, false if the file was a duplicate and * allow_duplicates was set to false. */ -bool projectm_playlist_add_preset(projectm_playlist_handle instance, const char* filename, +PROJECTM_PLAYLIST_EXPORT bool projectm_playlist_add_preset(projectm_playlist_handle instance, const char* filename, bool allow_duplicates); /** @@ -277,7 +278,7 @@ bool projectm_playlist_add_preset(projectm_playlist_handle instance, const char* * @return True if the file was added to the playlist, false if the file was a duplicate and * allow_duplicates was set to false. */ -bool projectm_playlist_insert_preset(projectm_playlist_handle instance, const char* filename, +PROJECTM_PLAYLIST_EXPORT bool projectm_playlist_insert_preset(projectm_playlist_handle instance, const char* filename, uint32_t index, bool allow_duplicates); /** @@ -293,7 +294,7 @@ bool projectm_playlist_insert_preset(projectm_playlist_handle instance, const ch * current playlist. * @return The number of files added to the playlist. Ranges between 0 and count. */ -uint32_t projectm_playlist_add_presets(projectm_playlist_handle instance, const char** filenames, +PROJECTM_PLAYLIST_EXPORT uint32_t projectm_playlist_add_presets(projectm_playlist_handle instance, const char** filenames, uint32_t count, bool allow_duplicates); /** @@ -314,7 +315,7 @@ uint32_t projectm_playlist_add_presets(projectm_playlist_handle instance, const * current playlist. * @return The number of files added to the playlist. Ranges between 0 and count. */ -uint32_t projectm_playlist_insert_presets(projectm_playlist_handle instance, const char** filenames, +PROJECTM_PLAYLIST_EXPORT uint32_t projectm_playlist_insert_presets(projectm_playlist_handle instance, const char** filenames, uint32_t count, unsigned int index, bool allow_duplicates); /** @@ -325,7 +326,7 @@ uint32_t projectm_playlist_insert_presets(projectm_playlist_handle instance, con * removed. * @return True if the preset was removed from the playlist, false if the index was out of range. */ -bool projectm_playlist_remove_preset(projectm_playlist_handle instance, uint32_t index); +PROJECTM_PLAYLIST_EXPORT bool projectm_playlist_remove_preset(projectm_playlist_handle instance, uint32_t index); /** * @brief Removes a number of presets from the playlist from the specified position. @@ -336,7 +337,7 @@ bool projectm_playlist_remove_preset(projectm_playlist_handle instance, uint32_t * @param count The number of presets to remove from the given index. * @return The number of presets removed from the playlist. */ -uint32_t projectm_playlist_remove_presets(projectm_playlist_handle instance, uint32_t index, +PROJECTM_PLAYLIST_EXPORT uint32_t projectm_playlist_remove_presets(projectm_playlist_handle instance, uint32_t index, uint32_t count); /** @@ -344,14 +345,14 @@ uint32_t projectm_playlist_remove_presets(projectm_playlist_handle instance, uin * @param instance The playlist manager instance. * @return True if shuffle mode is enabled, false otherwise. */ -bool projectm_playlist_get_shuffle(projectm_playlist_handle instance); +PROJECTM_PLAYLIST_EXPORT bool projectm_playlist_get_shuffle(projectm_playlist_handle instance); /** * @brief Enable or disable shuffle mode. * @param instance The playlist manager instance. * @param shuffle True to enable random shuffling, false to play presets in playlist order. */ -void projectm_playlist_set_shuffle(projectm_playlist_handle instance, bool shuffle); +PROJECTM_PLAYLIST_EXPORT void projectm_playlist_set_shuffle(projectm_playlist_handle instance, bool shuffle); /** * @brief Sorts part or the whole playlist according to the given predicate and order. @@ -373,7 +374,7 @@ void projectm_playlist_set_shuffle(projectm_playlist_handle instance, bool shuff * @param predicate The predicate to use for sorting. Default is SORT_PREDICATE_FULL_PATH. * @param order The sort order. Default is SORT_ORDER_ASCENDING. */ -void projectm_playlist_sort(projectm_playlist_handle instance, uint32_t start_index, uint32_t count, +PROJECTM_PLAYLIST_EXPORT void projectm_playlist_sort(projectm_playlist_handle instance, uint32_t start_index, uint32_t count, projectm_playlist_sort_predicate predicate, projectm_playlist_sort_order order); /** @@ -381,7 +382,7 @@ void projectm_playlist_sort(projectm_playlist_handle instance, uint32_t start_in * @param instance The playlist manager instance. * @return The number of retries after failed preset switches. */ -uint32_t projectm_playlist_get_retry_count(projectm_playlist_handle instance); +PROJECTM_PLAYLIST_EXPORT uint32_t projectm_playlist_get_retry_count(projectm_playlist_handle instance); /** * @brief Sets the number of retries after failed preset switches. @@ -390,14 +391,14 @@ uint32_t projectm_playlist_get_retry_count(projectm_playlist_handle instance); * @param retry_count The number of retries after failed preset switches. Default is 5. Set to 0 * to simply forward the failure event from projectM. */ -void projectm_playlist_set_retry_count(projectm_playlist_handle instance, uint32_t retry_count); +PROJECTM_PLAYLIST_EXPORT void projectm_playlist_set_retry_count(projectm_playlist_handle instance, uint32_t retry_count); /** * @brief Returns the current playlist position. * @param instance The playlist manager instance. * @return The current playlist position. If the playlist is empty, 0 will be returned. */ -uint32_t projectm_playlist_get_position(projectm_playlist_handle instance); +PROJECTM_PLAYLIST_EXPORT uint32_t projectm_playlist_get_position(projectm_playlist_handle instance); /** * @brief Plays the preset at the requested playlist position and returns the actual playlist index. @@ -413,7 +414,7 @@ uint32_t projectm_playlist_get_position(projectm_playlist_handle instance); * @param hard_cut If true, the preset transition is instant. If true, a smooth transition is played. * @return The new playlist position. If the playlist is empty, 0 will be returned. */ -uint32_t projectm_playlist_set_position(projectm_playlist_handle instance, uint32_t new_position, +PROJECTM_PLAYLIST_EXPORT uint32_t projectm_playlist_set_position(projectm_playlist_handle instance, uint32_t new_position, bool hard_cut); /** @@ -428,7 +429,7 @@ uint32_t projectm_playlist_set_position(projectm_playlist_handle instance, uint3 * @param hard_cut If true, the preset transition is instant. If true, a smooth transition is played. * @return The new playlist position. If the playlist is empty, 0 will be returned. */ -uint32_t projectm_playlist_play_next(projectm_playlist_handle instance, bool hard_cut); +PROJECTM_PLAYLIST_EXPORT uint32_t projectm_playlist_play_next(projectm_playlist_handle instance, bool hard_cut); /** * @brief Plays the previous playlist item and returns the index of the new preset. @@ -442,7 +443,7 @@ uint32_t projectm_playlist_play_next(projectm_playlist_handle instance, bool har * @param hard_cut If true, the preset transition is instant. If true, a smooth transition is played. * @return The new playlist position. If the playlist is empty, 0 will be returned. */ -uint32_t projectm_playlist_play_previous(projectm_playlist_handle instance, bool hard_cut); +PROJECTM_PLAYLIST_EXPORT uint32_t projectm_playlist_play_previous(projectm_playlist_handle instance, bool hard_cut); /** * @brief Plays the last preset played in the history and returns the index of the preset. @@ -460,7 +461,7 @@ uint32_t projectm_playlist_play_previous(projectm_playlist_handle instance, bool * @param hard_cut If true, the preset transition is instant. If true, a smooth transition is played. * @return The new playlist position. If the playlist is empty, 0 will be returned. */ -uint32_t projectm_playlist_play_last(projectm_playlist_handle instance, bool hard_cut); +PROJECTM_PLAYLIST_EXPORT uint32_t projectm_playlist_play_last(projectm_playlist_handle instance, bool hard_cut); /** * @brief Sets a new filter list. @@ -499,7 +500,7 @@ uint32_t projectm_playlist_play_last(projectm_playlist_handle instance, bool har * @param filter_list An array with filter strings. * @param count The size of the filter array. */ -void projectm_playlist_set_filter(projectm_playlist_handle instance, const char** filter_list, +PROJECTM_PLAYLIST_EXPORT void projectm_playlist_set_filter(projectm_playlist_handle instance, const char** filter_list, size_t count); /** @@ -512,7 +513,7 @@ void projectm_playlist_set_filter(projectm_playlist_handle instance, const char* * @param[out] count The size of the filter array. * @return An array with filter strings. */ -char** projectm_playlist_get_filter(projectm_playlist_handle instance, size_t* count); +PROJECTM_PLAYLIST_EXPORT char** projectm_playlist_get_filter(projectm_playlist_handle instance, size_t* count); /** * @brief Applies the current filter list to the existing playlist. @@ -523,7 +524,7 @@ char** projectm_playlist_get_filter(projectm_playlist_handle instance, size_t* c * @param instance The playlist manager instance. * @return The number of removed items. */ -size_t projectm_playlist_apply_filter(projectm_playlist_handle instance); +PROJECTM_PLAYLIST_EXPORT size_t projectm_playlist_apply_filter(projectm_playlist_handle instance); #ifdef __cplusplus } diff --git a/src/sdl-test-ui/CMakeLists.txt b/src/sdl-test-ui/CMakeLists.txt index 4a350d15d..37fd5cfa9 100644 --- a/src/sdl-test-ui/CMakeLists.txt +++ b/src/sdl-test-ui/CMakeLists.txt @@ -18,8 +18,7 @@ add_executable(projectM-Test-UI target_link_libraries(projectM-Test-UI PRIVATE - projectM::libprojectM - projectM::playlist + libprojectM::playlist GLM::GLM SDL2::SDL2 SDL2::SDL2main diff --git a/tests/libprojectM/CMakeLists.txt b/tests/libprojectM/CMakeLists.txt index 6cfcbeaa5..9e3c0108e 100644 --- a/tests/libprojectM/CMakeLists.txt +++ b/tests/libprojectM/CMakeLists.txt @@ -2,6 +2,12 @@ find_package(GTest 1.10 REQUIRED NO_MODULE) add_executable(projectM-unittest PCMTest.cpp + + $ + $ + $ + $ + $ ) target_compile_definitions(projectM-unittest @@ -18,7 +24,7 @@ target_include_directories(projectM-unittest target_link_libraries(projectM-unittest PRIVATE - projectM_static + projectM_main GTest::gtest GTest::gtest_main ) diff --git a/tests/playlist/CMakeLists.txt b/tests/playlist/CMakeLists.txt index d17277a97..91ae5f42a 100644 --- a/tests/playlist/CMakeLists.txt +++ b/tests/playlist/CMakeLists.txt @@ -5,12 +5,14 @@ endif() find_package(GTest 1.10 REQUIRED NO_MODULE) add_executable(projectM-playlist-unittest + $ APITest.cpp ItemTest.cpp PlaylistCWrapperMock.h PlaylistTest.cpp ProjectMAPIMocks.cpp - FilterTest.cpp) + FilterTest.cpp + ) target_compile_definitions(projectM-playlist-unittest PRIVATE @@ -19,7 +21,7 @@ target_compile_definitions(projectM-playlist-unittest target_link_libraries(projectM-playlist-unittest PRIVATE - projectM_playlist + projectM_playlist_main GTest::gmock GTest::gtest GTest::gtest_main