Only build either shared or static projectM and playlist libraries.

Target name is now just libprojectM::projectM for the main library instead of libprojectM::static or libprojectM::shared.

Now using CMake's default mechanism to select the resulting library type via the BUILD_SHARED_LIBS variable. Main use case will be working with the shared library, which is the default.

Playlist library now also builds as a shared library, including proper symbol exports.

Additionally, deleted the leftover TestRunner class and a few old and rather useless test cases.

Also added LLVM find_package call and as a link dependency if the build is configured for using (experimental) LLVM code.

Reorganized tests to link either one of the object libraries for unit testing.
This commit is contained in:
Kai Blaschke
2023-01-08 02:05:51 +01:00
parent f2615a1745
commit 6e795ec632
16 changed files with 241 additions and 570 deletions

View File

@ -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}")

View File

@ -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

View File

@ -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.
$<TARGET_OBJECTS:MilkdropPresetFactory>
$<TARGET_OBJECTS:Renderer>
$<TARGET_OBJECTS:hlslparser>
$<TARGET_OBJECTS:SOIL2>
$<TARGET_OBJECTS:projectM_main>
)
if (ENABLE_STATIC_LIB)
include(libprojectM_static.cmake)
target_include_directories(projectM
PUBLIC
"$<INSTALL_INTERFACE:${PROJECTM_INCLUDE_DIR}>"
)
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 $<IF:$<PLATFORM_ID:Windows>,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()

View File

@ -1048,195 +1048,6 @@ Expr *Expr::create_program_expr(std::vector<Expr*> &steps_, bool ownSteps)
}
// TESTS
#include <TestRunner.hpp>
#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;

View File

@ -392,37 +392,3 @@ Param * Param::createUser( const std::string &name )
{
return new _FloatParam( name );
}
// TESTS
#include <TestRunner.hpp>
#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

View File

@ -1,49 +0,0 @@
//
// Created by matthew on 1/7/19.
//
#include <iostream>
#include <TestRunner.hpp>
#include <MilkdropPresetFactory/Param.hpp>
std::vector<Test *> 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;
}

View File

@ -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 <string>
#include <vector>
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<Test *> tests;
};
#endif //PROJECTM_LUA_TESTRUNNER_H

View File

@ -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)

View File

@ -1,77 +0,0 @@
add_library(projectM_shared SHARED
ProjectMCWrapper.cpp
ProjectMCWrapper.hpp
$<TARGET_OBJECTS:projectM_main>
$<TARGET_OBJECTS:MilkdropPresetFactory>
$<TARGET_OBJECTS:Renderer>
$<TARGET_OBJECTS:hlslparser>
$<TARGET_OBJECTS:SOIL2>
)
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
"$<INSTALL_INTERFACE:${PROJECTM_INCLUDE_DIR}>"
)
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)

View File

@ -1,92 +0,0 @@
add_library(projectM_static STATIC
ProjectMCWrapper.cpp
ProjectMCWrapper.hpp
$<TARGET_OBJECTS:projectM_main>
$<TARGET_OBJECTS:MilkdropPresetFactory>
$<TARGET_OBJECTS:Renderer>
$<TARGET_OBJECTS:hlslparser>
$<TARGET_OBJECTS:SOIL2>
)
target_compile_definitions(projectM_static
PUBLIC
PROJECTM_STATIC_DEFINE
)
set_target_properties(projectM_static PROPERTIES
OUTPUT_NAME $<IF:$<PLATFORM_ID:Windows>,libprojectM,projectM>
EXPORT_NAME static
FOLDER libprojectM
)
target_include_directories(projectM_static
PUBLIC
"$<INSTALL_INTERFACE:${PROJECTM_INCLUDE_DIR}>"
)
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()

View File

@ -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.
$<TARGET_OBJECTS:projectM_playlist_main>
)
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
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
"$<INSTALL_INTERFACE:${PROJECTM_INCLUDE_DIR}>"
)
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 $<IF:$<PLATFORM_ID:Windows>,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
)

View File

@ -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=<filesystem>
@ -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=<boost/filesystem.hpp>
)
target_link_libraries(projectM_playlist_main
PUBLIC
Boost::filesystem
)
target_link_libraries(projectM_playlist
PUBLIC
Boost::filesystem

View File

@ -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
}

View File

@ -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

View File

@ -2,6 +2,12 @@ find_package(GTest 1.10 REQUIRED NO_MODULE)
add_executable(projectM-unittest
PCMTest.cpp
$<TARGET_OBJECTS:MilkdropPresetFactory>
$<TARGET_OBJECTS:Renderer>
$<TARGET_OBJECTS:hlslparser>
$<TARGET_OBJECTS:SOIL2>
$<TARGET_OBJECTS:projectM_main>
)
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
)

View File

@ -5,12 +5,14 @@ endif()
find_package(GTest 1.10 REQUIRED NO_MODULE)
add_executable(projectM-playlist-unittest
$<TARGET_OBJECTS:projectM_playlist_main>
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