diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | CMakeLists.txt | 322 | ||||
-rw-r--r-- | Plugin.cmake | 45 | ||||
-rw-r--r-- | README.md | 20 | ||||
-rw-r--r-- | cmake/CompilerOptimizations.cmake | 53 | ||||
-rw-r--r-- | cmake/Modules/FindCsound.cmake | 53 | ||||
-rw-r--r-- | cmake/Modules/FindPQXX.cmake | 33 | ||||
-rw-r--r-- | cmake/Modules/FindPackageHandleStandardArgs.cmake | 611 | ||||
-rw-r--r-- | cmake/Modules/FindPackageMessage.cmake | 48 | ||||
-rw-r--r-- | cmake/Modules/FindPostgreSQL.cmake | 315 | ||||
-rw-r--r-- | cmake/Modules/SelectLibraryConfigurations.cmake | 80 | ||||
-rw-r--r-- | include/connection.h | 6 | ||||
-rw-r--r-- | include/logindata.h | 4 | ||||
-rw-r--r-- | include/mysql.h | 6 | ||||
-rw-r--r-- | include/postgresql.h | 14 | ||||
-rw-r--r-- | include/sqlite.h | 6 | ||||
-rw-r--r-- | include/tools.h | 30 | ||||
-rw-r--r-- | src/connection.cpp | 10 | ||||
-rw-r--r-- | src/mysql.cpp | 32 | ||||
-rw-r--r-- | src/opcodes.cpp | 99 | ||||
-rw-r--r-- | src/postgresql.cpp | 90 | ||||
-rw-r--r-- | src/sqlite3.cpp | 44 | ||||
-rw-r--r-- | src/tools.cpp | 54 |
23 files changed, 1590 insertions, 386 deletions
@@ -1,2 +1 @@ build/ -examples-test/
\ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 43c251d..8c47998 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,217 +1,201 @@ -project("csound_sqldb") +# from https://github.com/csound/plugins : common CMake operations +cmake_minimum_required(VERSION 2.8.12) +project(Csound-plugins) -cmake_minimum_required(VERSION 3.8) - -set(APIVERSION "6.0") +if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") + set(CMAKE_COMPILER_IS_CLANG 1) +endif() -# Release or Debug -set(CMAKE_BUILD_TYPE "Release") +# C++11 needed +if(NOT MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +endif() -# force make to print the command lines -set(CMAKE_VERBOSE_MAKEFILE on) +set(APIVERSION "6.0") -# path to Csound cmake module +set(CMAKE_MACOSX_RPATH 1) +set(CMAKE_VERBOSE_MAKEFILE ON) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") -# set compilation flags -set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-std=c++11 -fpermissive -fPIC -w -DUSE_DOUBLE -DB64BIT") - -# options -option(USE_LIB64 "Set to on to set installation dir for libs to lib64" OFF) -option(USE_DOUBLE "Use doubles for audio calculations" ON) -option(CPP11 "c++11" ON) - -set(BUILDING_CSOUND_PLUGINS ON) - -# ---------------------------------------------- - -include(FindCsound) -include(FindPQXX) -include(FindSqlite3) -include(FindMySQL) - +include(TestBigEndian) +include(CheckFunctionExists) include(CheckCCompilerFlag) include(CheckCXXCompilerFlag) -# ----------------------------------------------- - -function(addflag flag flagname) - check_c_compiler_flag(${flag} ${flagname}) - if (${flagname}) - # message(STATUS "Setting C flag ${flag}") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${flag}" PARENT_SCOPE) - endif() - check_cxx_compiler_flag(${flag} CXX_${flagname}) - if (CXX_${flagname}) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}" PARENT_SCOPE) - endif() -endfunction(addflag) - - -MACRO(SUBDIRLIST result curdir) - FILE(GLOB children RELATIVE ${curdir} ${curdir}/*) - SET(dirlist "") - FOREACH(child ${children}) - message(STATUS "looking at ${child}") - IF(IS_DIRECTORY ${curdir}/${child}) - LIST(APPEND dirlist ${child}) - ENDIF() - ENDFOREACH() - SET(${result} ${dirlist}) -ENDMACRO() - - -MACRO(ADD_ALL_SUBDIRECTORIES directory) - subdirlist(SUBDIRS ${directory}) - message(STATUS "Found subdirs: ${SUBDIRS}") - foreach(SUBDIR ${SUBDIRS}) - set(thissubdir "${directory}/${SUBDIR}") - if(EXISTS "${directory}/${SUBDIR}/CMakeLists.txt") - message(STATUS "Adding subdir: ${thissubdir}") - add_subdirectory(${directory}/${SUBDIR}) - else() - message(WARNING "Skipping ${directory}/${SUBDIR} because no CMakeLists.txt file was found") - endif() - endforeach() -ENDMACRO() +### COMPILER OPTIMIZATION FLAGS +option(USE_COMPILER_OPTIMIZATIONS "Use the default Csound compiler optimization flags" ON) +if(USE_COMPILER_OPTIMIZATIONS) + include(${CMAKE_SOURCE_DIR}/cmake/CompilerOptimizations.cmake) +endif() +if(APPLE) + set(OSX_VERSION " ") +endif() +## USER OPTIONS ## +# Optional targets, they should all default to ON (check_deps will disable them if not possible to build) +option(USE_DOUBLE "Set to use double-precision floating point for audio samples." ON) -# set optimization flags -if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG) - add_definitions(-fvisibility=hidden) - if(NATIVE) - add_definitions(-march=native) - endif() - - include(CheckCCompilerFlag) - include(CheckCXXCompilerFlag) - addflag(-msse HAS_SSE) - addflag(-msse2 HAS_SSE2) - addflag(-mfgpath=sse HAS_FPMATH_SSE) - +# in Release configuration, set NDEBUG +if(${CMAKE_BUILD_TYPE} MATCHES "Release") +message("-----> Release mode") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNDEBUG") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNDEBUG") +elseif(${CMAKE_BUILD_TYPE} MATCHES "Debug") +message("-----> Debug mode") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBETA") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DBETA") endif() -if(MINGW) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mstackrealign") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mstackrealign") +# set -Werror if in Debug configuration +if(NOT MSVC AND NOT WASM) + set(CMAKE_CXX_FLAGS_RELEASE "-O3 ") + set(CMAKE_C_FLAGS_RELEASE "-O3 ") + if(${CMAKE_BUILD_TYPE} MATCHES "Debug") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Wno-missing-field-initializers") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -Wno-missing-field-initializers") + endif() endif() -addflag(-ftree-vectorize HAS_TREE_VECTORIZE) -addflag(-ffast-math HAS_FAST_MATH) -addflag(-fomit-frame-pointer HAS_OMIT_FRAME_POINTER) +if(CMAKE_SYSTEM_NAME MATCHES "Linux") + set(LINUX YES) +else() + set(LINUX NO) +endif() + +set(BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}) -# ------------------------------------------------------------------- +check_c_compiler_flag(-fvisibility=hidden HAS_VISIBILITY_HIDDEN) +check_cxx_compiler_flag(-fvisibility=hidden HAS_CXX_VISIBILITY_HIDDEN) +if (HAS_VISIBILITY_HIDDEN) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden") +endif() +if (HAS_CXX_VISIBILITY_HIDDEN) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden") +endif() -set(CS_FRAMEWORK_DEST "~/Library/Frameworks") +check_c_compiler_flag(-std=gnu99 HAS_GNU99) +if (HAS_GNU99) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") +endif() +if (HAS_CXX_VISIBILITY_HIDDEN) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden") +endif() +find_package(Csound) +option(USE_LIB64 "Set to on to set installation directory for libraries to lib64" OFF) if(USE_LIB64) - set(LIBRARY_INSTALL_DIR "lib64") - add_definitions("-DLIB64") + set(LIBRARY_INSTALL_DIR "lib64") + add_definitions("-DLIB64") else() - set(LIBRARY_INSTALL_DIR "lib") + set(LIBRARY_INSTALL_DIR "lib") endif() - message(STATUS "LIBRARY INSTALL DIR: ${LIBRARY_INSTALL_DIR}") -# ------------------------------------------------------------------- - - if(USE_DOUBLE) - message(STATUS ">>> using doubles") - - if(APPLE) - set(CSOUNDLIB "CsoundLib64") - set(PLUGIN_INSTALL_DIR "${CS_FRAMEWORK_DEST}/${CSOUNDLIB}.framework/Versions/${APIVERSION}/Resources/Opcodes64") - else() - set(CSOUNDLIB "csound64") + message(STATUS "Building with 64-bit floats") set(PLUGIN_INSTALL_DIR "${LIBRARY_INSTALL_DIR}/csound/plugins64-${APIVERSION}") - endif() + if(APPLE) + set(PLUGIN_INSTALL_DIR "${CS_FRAMEWORK_DEST}/${CSOUNDLIB}.framework/Versions/${APIVERSION}/Resources/Opcodes64") + endif() else() - message(STATUS ">>> not using doubles") - if(APPLE) - set(CSOUNDLIB "CsoundLib") - set(PLUGIN_INSTALL_DIR "${CS_FRAMEWORK_DEST}/${CSOUNDLIB}.framework/Versions/${APIVERSION}/Resources/Opcodes") - else() - set(CSOUNDLIB "csound") + message(STATUS "Building with 32-bit floats") set(PLUGIN_INSTALL_DIR "${LIBRARY_INSTALL_DIR}/csound/plugins-${APIVERSION}") - endif() + if(APPLE) + set(PLUGIN_INSTALL_DIR "${CS_FRAMEWORK_DEST}/${CSOUNDLIB}.framework/Versions/${APIVERSION}/Resources/Opcodes") + endif() endif() -# ------------------------------------------------------------------- - -# Csound opcode build -find_package(Csound) - - -set(BUILD_PLUGINS_DIR ${CMAKE_CURRENT_BINARY_DIR}) - -if(NOT CSOUND_FOUND) - message(FATAL_ERROR "Csound installation not found") -endif() - -if(NOT PQXX_FOUND AND NOT SQLITE3_FOUND AND NOT MYSQLCONNECTORCPP_FOUND) - message(FATAL_ERROR "No database libraries could be found") -endif() +# Checks if dependencies for an enabled target are fulfilled. +# If FAIL_MISSING is true and the dependencies are not fulfilled, +# it will abort the cmake run. +# If FAIL_MISSING is false, it will set the option to OFF. +# If the target is not enabled, it will do nothing. +# example: check_deps(BUILD_NEW_PARSER FLEX_EXECUTABLE BISON_EXECUTABLE) +function(check_deps option) + if(${option}) + set(i 1) + while( ${i} LESS ${ARGC} ) + set(dep ${ARGV${i}}) + if(NOT ${dep}) + if(FAIL_MISSING) + message(FATAL_ERROR + "${option} is enabled, but ${dep}=\"${${dep}}\"") + else() + message(STATUS "${dep}=\"${${dep}}\", so disabling ${option}") + set(${option} OFF PARENT_SCOPE) + # Set it in the local scope too + set(${option} OFF) + endif() + endif() + math(EXPR i "${i}+1") + endwhile() + endif() + if(${option}) + message(STATUS "${option} is enabled.") + else() + message(STATUS "${option} is disabled.") + endif() +endfunction(check_deps) +# Utility function to make plugins. All plugin targets should use this as it +# sets up output directory set in top-level CmakeLists.txt +# and adds the appropriate install target # -#if(APPLE) -# add_library(sqldb SHARED ${srcs}) -#else() -# add_library(sqldb MODULE ${srcs}) -#endif() - -set(CPPFILES src/opcodes.cpp src/connection.cpp) - - -if (PQXX_FOUND) - message(STATUS "Using PostgreSQL") - list(APPEND CPPFILES "src/postgresql.cpp") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBUILD_POSTGRES") -endif() +# libname - name of library to produce +# srcs - list of src files (must be quoted if a list) +# extralibs (OPTIONAL) - extra libraries to link the plugin to +# +# NB - this was moved here as it needs some VARS defined above +# for setting up the framework +function(make_plugin libname srcs) + if(APPLE) + add_library(${libname} SHARED ${srcs}) + else() + add_library(${libname} MODULE ${srcs}) + endif() -if (SQLITE3_FOUND) - message(STATUS "Using SQLite3") - list(APPEND CPPFILES "src/sqlite3.cpp") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBUILD_SQLITE") -endif() + set(i 2) + while( ${i} LESS ${ARGC} ) + target_link_libraries(${libname} ${ARGV${i}}) + math(EXPR i "${i}+1") + endwhile() -if (MYSQLCONNECTORCPP_FOUND) - message(STATUS "Using MySQL") - list(APPEND CPPFILES "src/mysql.cpp") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBUILD_MYSQL") -endif() + set_target_properties(${libname} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + install(TARGETS ${libname} + LIBRARY DESTINATION "${PLUGIN_INSTALL_DIR}" + ARCHIVE DESTINATION "${PLUGIN_INSTALL_DIR}" ) +endfunction(make_plugin) +# Linux does not have a separate libintl, it is part of libc +set(LIBINTL_AVAIL (LIBINTL_LIBRARY OR LINUX)) -#include_directories(/usr/include) -include_directories(${CSOUND_INCLUDE_DIRS}) -include_directories(include) +if(LINUX) + message(STATUS "Building on Linux.") + add_definitions(-DLINUX -DPIPES -D_GNU_SOURCE -DHAVE_SOCKETS) + list(APPEND libcsound_LIBS ${MATH_LIBRARY} dl) -if (PQXX_FOUND) - link_libraries(${PQXX_LIBRARIES}) - include_directories(${PQXX_INCLUDE_DIRECTORIES}) endif() -if (SQLITE3_FOUND) - link_libraries(${SQLITE3_LIBRARIES}) - include_directories(${SQLITE3_INCLUDE_DIRS}) +if(APPLE AND NOT IOS) + message(STATUS "Building on OSX") + add_definitions(-DMACOSX -DPIPES -DNO_FLTK_THREADS -DHAVE_SOCKETS) + find_library(ACCELERATE_LIBRARY Accelerate) + find_path(VECLIB_PATH "Accelerate/Accelerate.h") + include_directories(${VECLIB_PATH}) + list(APPEND libcsound_LIBS ${MATH_LIBRARY} dl ${ACCELERATE_LIBRARY}) endif() -if (MYSQLCONNECTORCPP_FOUND) - link_libraries(${MYSQLCONNECTORCPP_LIBRARIES}) - include_directories(${MYSQLCONNECTORCPP_INCLUDE_DIRS}) +if(WIN32) + add_definitions(-DWIN32) endif() -add_library(sqldb SHARED ${CPPFILES}) - -set_target_properties(sqldb PROPERTIES - RUNTIME_OUTPUT_DIRECTORY ${BUILD_PLUGINS_DIR} - LIBRARY_OUTPUT_DIRECTORY ${BUILD_PLUGINS_DIR}) - -install(TARGETS sqldb LIBRARY DESTINATION "${PLUGIN_INSTALL_DIR}" ) - +include(Plugin.cmake) diff --git a/Plugin.cmake b/Plugin.cmake new file mode 100644 index 0000000..febebda --- /dev/null +++ b/Plugin.cmake @@ -0,0 +1,45 @@ +set(PLUGIN_NAME sqldb) + +# Dependencies +find_package(PostgreSQL) +find_package(Sqlite3) +find_package(MySQL) + +# Check databases available +if(NOT PostgreSQL_FOUND AND NOT SQLITE3_FOUND AND NOT MYSQLCONNECTORCPP_FOUND) + message(FATAL_ERROR "No database libraries could be found") +endif() + +# Source files +set(CPPFILES src/opcodes.cpp src/connection.cpp src/tools.cpp) +set(INCLUDES ${CSOUND_INCLUDE_DIRS} "include") +set(LIBS "") + +if(PostgreSQL_FOUND) + message(STATUS "Using PostgreSQL") + list(APPEND CPPFILES "src/postgresql.cpp") + list(APPEND INCLUDES ${PostgreSQL_INCLUDE_DIRS}) + list(APPEND LIBS ${PostgreSQL_LIBRARIES}) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBUILD_POSTGRES") +endif() + +if(SQLITE3_FOUND) + message(STATUS "Using SQLite3") + list(APPEND CPPFILES "src/sqlite3.cpp") + list(APPEND INCLUDES ${SQLITE3_INCLUDE_DIRS}) + list(APPEND LIBS ${SQLITE3_LIBRARIES}) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBUILD_SQLITE") +endif() + +if(MYSQLCONNECTORCPP_FOUND) + message(STATUS "Using MySQL") + list(APPEND CPPFILES "src/mysql.cpp") + list(APPEND INCLUDES ${MYSQLCONNECTORCPP_INCLUDE_DIRS}) + list(APPEND LIBS ${MYSQLCONNECTORCPP_LIBRARIES}) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBUILD_MYSQL") +endif() + + +make_plugin(${PLUGIN_NAME} "${CPPFILES}" ${LIBS}) +target_include_directories(${PLUGIN_NAME} PRIVATE ${INCLUDES}) + @@ -1,11 +1,12 @@ ## Introduction csound-sqldb provides database access opcodes which allow for the querying of data in SQL databases at i- and k-rate. -MySQL, PostgreSQL and SQLite3 are supported and are used with the same opcodes after the initial connection. The opcodes have currently been tested on Linux only. +MySQL, PostgreSQL and SQLite3 are supported and are used with the same opcodes after the initial connection. The opcodes have been tested on Linux and Windows. The opcodes rely on changes made after the official 6.13.0 release of Csound so while awaiting the next release the Csound source will need to be obtained from the develop branch of https://github.com/csound/csound/ otherwise they will not build. ## Opcode overview The opcodes are detailed in full in OpcodeDocumentation.md + Aside from the connection opcode, there are three groups available for each to allow for design options particularly when considering database latency/performance: - i-rate : to be used when db latency is particularly low, in global orchestra space or not running in realtime etc. @@ -15,30 +16,30 @@ Aside from the connection opcode, there are three groups available for each to a ## Requirements - Csound libraries - - Cmake + - Cmake >= 2.8.12 - At least one database development library from the three below. Opcodes will support whichever of these databases can be found, which will be indicated when running the initial cmake command. ### MySQL Connector/C++ (https://dev.mysql.com/downloads/connector/cpp/) - # apt get install libmysqlcppconn-dev + # apt-get install libmysqlcppconn-dev ### PostgreSQL -libpqxx (http://pqxx.org/development/libpqxx/wiki/DownloadPage) +libpq (https://www.postgresql.org/download/) - # apt get install libpqxx-dev + # apt-get install libpq-dev ### SQLite libsqlite (https://www.sqlite.org/download.html) - # apt get install libsqlite3-dev + # apt-get install libsqlite3-dev ## Building Create a build directory at the top of the source tree, execute *cmake ..*, *make* and optionally *make install* as root. If the latter is not used/possible then the resulting libsqldb.so can be used with the *--opcode-lib* flag in Csound. eg: - git clone https://github.com/1bpm/csound-sqldb.git + git clone https://git.1bpm.net/csound-sqldb cd csound-sqldb mkdir build && cd build cmake .. @@ -47,6 +48,7 @@ eg: ## Examples A number of examples are included in the examples directory. Generally the syntax of each opcode is agnostic to the database type used, so the different techniques in each can be used for any database type. +## Reference +OpcodeDocumentation.md contains an explanation of all provided opcodes. - -By Richard Knight 2019
\ No newline at end of file +By Richard Knight 2019 diff --git a/cmake/CompilerOptimizations.cmake b/cmake/CompilerOptimizations.cmake new file mode 100644 index 0000000..543daf8 --- /dev/null +++ b/cmake/CompilerOptimizations.cmake @@ -0,0 +1,53 @@ +
+check_c_compiler_flag(-ftree-vectorize HAS_TREE_VECTORIZE)
+check_cxx_compiler_flag(-ftree-vectorize HAS_CXX_TREE_VECTORIZE)
+if (HAS_TREE_VECTORISE)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ftree-vectorize")
+endif()
+if (HAS_CXX_TREE_VECTORISE)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftree-vectorize")
+endif()
+
+
+check_c_compiler_flag(-ffast-math HAS_FAST_MATH)
+check_cxx_compiler_flag(-ffast-math HAS_CXX_FAST_MATH)
+if (HAS_FAST_MATH AND NOT MINGW)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffast-math")
+endif()
+if (HAS_CXX_FAST_MATH AND NOT MINGW)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math")
+endif()
+
+
+
+if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+check_c_compiler_flag(-mfpmath=sse HAS_FPMATH_SSE)
+check_cxx_compiler_flag(-mfpmath=sse HAS_CXX_FPMATH_SSE)
+ if (HAS_FPMATH_SSE)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpmath=sse")
+endif()
+if (HAS_CXX_FPMATH_SSE)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpmath=sse")
+endif()
+
+endif()
+
+
+check_c_compiler_flag(-msse2 HAS_SSE2)
+check_cxx_compiler_flag(-msse2 HAS_CXX_SSE2)
+ if (HAS_SSE2 AND NOT IOS AND NOT WASM)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse2")
+endif()
+if (HAS_CXX_SSE2 AND NOT IOS AND NOT WASM)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse2")
+endif()
+
+
+check_c_compiler_flag(-fomit-frame-pointer HAS_OMIT_FRAME_POINTER)
+check_cxx_compiler_flag(-fomit-frame-pointer HAS_CXX_OMIT_FRAME_POINTER)
+if (HAS_OMIT_FRAME_POINTER)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fomit-frame-pointer")
+endif()
+if (HAS_CXX_OMIT_FRAME_POINTER)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fomit-frame-pointer")
+endif()
diff --git a/cmake/Modules/FindCsound.cmake b/cmake/Modules/FindCsound.cmake index e55b269..24c90d9 100644 --- a/cmake/Modules/FindCsound.cmake +++ b/cmake/Modules/FindCsound.cmake @@ -4,20 +4,53 @@ # CSOUND_INCLUDE_DIRS - The Csound include directories. # CSOUND_LIBRARIES - The libraries needed to use the Csound library. -if(APPLE) -find_path(CSOUND_INCLUDE_DIR csound.h HINTS /Library/Frameworks/CsoundLib64.framework/Headers -"$ENV{HOME}/Library/Frameworks/CsoundLib64.framework/Headers") -else() -find_path(CSOUND_INCLUDE_DIR csound.h PATH_SUFFIXES csound) -endif() +# RKnight 2021-07-21 : quick copy paste hack to deal with 32 bit if not using double + +if(USE_DOUBLE) + # 64 bit + if(APPLE) + find_path(CSOUND_INCLUDE_DIR csound.h HINTS /Library/Frameworks/CsoundLib64.framework/Headers + "$ENV{HOME}/Library/Frameworks/CsoundLib64.framework/Headers") + elseif(WIN32) + find_path(CSOUND_INCLUDE_DIR csound.h PATH_SUFFIXES csound + HINTS "c:\\Program Files\\Csound6_x64\\include") + else() + find_path(CSOUND_INCLUDE_DIR csound.h PATH_SUFFIXES csound) + endif() + + if(APPLE) + find_library(CSOUND_LIBRARY NAMES CsoundLib64 HINTS /Library/Frameworks/CsoundLib64.framework/ + "$ENV{HOME}/Library/Frameworks/CsoundLib64.framework") + elseif(WIN32) + find_library(CSOUND_LIBRARY NAMES csound64 HINTS "c:\\Program Files\\Csound6_x64\\lib") + else() + find_library(CSOUND_LIBRARY NAMES csound64 csound) + endif() -if(APPLE) -find_library(CSOUND_LIBRARY NAMES CsoundLib64 HINTS /Library/Frameworks/CsoundLib64.framework/ -"$ENV{HOME}/Library/Frameworks/CsoundLib64.framework") else() -find_library(CSOUND_LIBRARY NAMES csound64 csound) + # 32 bit + if(APPLE) + find_path(CSOUND_INCLUDE_DIR csound.h HINTS /Library/Frameworks/CsoundLib.framework/Headers + "$ENV{HOME}/Library/Frameworks/CsoundLib.framework/Headers") + elseif(WIN32) + find_path(CSOUND_INCLUDE_DIR csound.h PATH_SUFFIXES csound + HINTS "c:\\Program Files (x86)\\Csound6\\include") + else() + find_path(CSOUND_INCLUDE_DIR csound.h PATH_SUFFIXES csound) + endif() + + if(APPLE) + find_library(CSOUND_LIBRARY NAMES CsoundLib HINTS /Library/Frameworks/CsoundLib.framework/ + "$ENV{HOME}/Library/Frameworks/CsoundLib.framework") + elseif(WIN32) + find_library(CSOUND_LIBRARY NAMES csound HINTS "c:\\Program Files (x86)\\Csound6\\lib") + else() + find_library(CSOUND_LIBRARY NAMES csound csound) + endif() + endif() + include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set CSOUND_FOUND to TRUE # if all listed variables are TRUE diff --git a/cmake/Modules/FindPQXX.cmake b/cmake/Modules/FindPQXX.cmake deleted file mode 100644 index 724079b..0000000 --- a/cmake/Modules/FindPQXX.cmake +++ /dev/null @@ -1,33 +0,0 @@ -# - Find libpqxx -# Find the libpqxx includes and client library -# This module defines -# PQXX_INCLUDE_DIRS -# PQXX_LIBRARIES -# PQXX_FOUND - -include (FindPackageHandleStandardArgs) - -find_path (PQXX_INCLUDE_DIRS - NAME - pqxx - PATHS - /usr/include - /usr/local/include - PATH_SUFFIXES - pqxx - DOC - "Directory for pqxx headers" -) - -find_library (PQXX_LIBRARIES - NAMES - pqxx -) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS("PQXX" - "libpqxx couldn't be found" - PQXX_LIBRARIES - PQXX_INCLUDE_DIRS -) - -mark_as_advanced (PQXX_INCLUDE_DIR PQXX_LIBRARY)
\ No newline at end of file diff --git a/cmake/Modules/FindPackageHandleStandardArgs.cmake b/cmake/Modules/FindPackageHandleStandardArgs.cmake new file mode 100644 index 0000000..56ba1e6 --- /dev/null +++ b/cmake/Modules/FindPackageHandleStandardArgs.cmake @@ -0,0 +1,611 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +FindPackageHandleStandardArgs +----------------------------- + +This module provides functions intended to be used in :ref:`Find Modules` +implementing :command:`find_package(<PackageName>)` calls. + +.. command:: find_package_handle_standard_args + + This command handles the ``REQUIRED``, ``QUIET`` and version-related + arguments of :command:`find_package`. It also sets the + ``<PackageName>_FOUND`` variable. The package is considered found if all + variables listed contain valid results, e.g. valid filepaths. + + There are two signatures: + + .. code-block:: cmake + + find_package_handle_standard_args(<PackageName> + (DEFAULT_MSG|<custom-failure-message>) + <required-var>... + ) + + find_package_handle_standard_args(<PackageName> + [FOUND_VAR <result-var>] + [REQUIRED_VARS <required-var>...] + [VERSION_VAR <version-var>] + [HANDLE_VERSION_RANGE] + [HANDLE_COMPONENTS] + [CONFIG_MODE] + [NAME_MISMATCHED] + [REASON_FAILURE_MESSAGE <reason-failure-message>] + [FAIL_MESSAGE <custom-failure-message>] + ) + + The ``<PackageName>_FOUND`` variable will be set to ``TRUE`` if all + the variables ``<required-var>...`` are valid and any optional + constraints are satisfied, and ``FALSE`` otherwise. A success or + failure message may be displayed based on the results and on + whether the ``REQUIRED`` and/or ``QUIET`` option was given to + the :command:`find_package` call. + + The options are: + + ``(DEFAULT_MSG|<custom-failure-message>)`` + In the simple signature this specifies the failure message. + Use ``DEFAULT_MSG`` to ask for a default message to be computed + (recommended). Not valid in the full signature. + + ``FOUND_VAR <result-var>`` + .. deprecated:: 3.3 + + Specifies either ``<PackageName>_FOUND`` or + ``<PACKAGENAME>_FOUND`` as the result variable. This exists only + for compatibility with older versions of CMake and is now ignored. + Result variables of both names are always set for compatibility. + + ``REQUIRED_VARS <required-var>...`` + Specify the variables which are required for this package. + These may be named in the generated failure message asking the + user to set the missing variable values. Therefore these should + typically be cache entries such as ``FOO_LIBRARY`` and not output + variables like ``FOO_LIBRARIES``. + + .. versionchanged:: 3.18 + If ``HANDLE_COMPONENTS`` is specified, this option can be omitted. + + ``VERSION_VAR <version-var>`` + Specify the name of a variable that holds the version of the package + that has been found. This version will be checked against the + (potentially) specified required version given to the + :command:`find_package` call, including its ``EXACT`` option. + The default messages include information about the required + version and the version which has been actually found, both + if the version is ok or not. + + ``HANDLE_VERSION_RANGE`` + .. versionadded:: 3.19 + + Enable handling of a version range, if one is specified. Without this + option, a developer warning will be displayed if a version range is + specified. + + ``HANDLE_COMPONENTS`` + Enable handling of package components. In this case, the command + will report which components have been found and which are missing, + and the ``<PackageName>_FOUND`` variable will be set to ``FALSE`` + if any of the required components (i.e. not the ones listed after + the ``OPTIONAL_COMPONENTS`` option of :command:`find_package`) are + missing. + + ``CONFIG_MODE`` + Specify that the calling find module is a wrapper around a + call to ``find_package(<PackageName> NO_MODULE)``. This implies + a ``VERSION_VAR`` value of ``<PackageName>_VERSION``. The command + will automatically check whether the package configuration file + was found. + + ``REASON_FAILURE_MESSAGE <reason-failure-message>`` + .. versionadded:: 3.16 + + Specify a custom message of the reason for the failure which will be + appended to the default generated message. + + ``FAIL_MESSAGE <custom-failure-message>`` + Specify a custom failure message instead of using the default + generated message. Not recommended. + + ``NAME_MISMATCHED`` + .. versionadded:: 3.17 + + Indicate that the ``<PackageName>`` does not match + ``${CMAKE_FIND_PACKAGE_NAME}``. This is usually a mistake and raises a + warning, but it may be intentional for usage of the command for components + of a larger package. + +Example for the simple signature: + +.. code-block:: cmake + + find_package_handle_standard_args(LibXml2 DEFAULT_MSG + LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR) + +The ``LibXml2`` package is considered to be found if both +``LIBXML2_LIBRARY`` and ``LIBXML2_INCLUDE_DIR`` are valid. +Then also ``LibXml2_FOUND`` is set to ``TRUE``. If it is not found +and ``REQUIRED`` was used, it fails with a +:command:`message(FATAL_ERROR)`, independent whether ``QUIET`` was +used or not. If it is found, success will be reported, including +the content of the first ``<required-var>``. On repeated CMake runs, +the same message will not be printed again. + +.. note:: + + If ``<PackageName>`` does not match ``CMAKE_FIND_PACKAGE_NAME`` for the + calling module, a warning that there is a mismatch is given. The + ``FPHSA_NAME_MISMATCHED`` variable may be set to bypass the warning if using + the old signature and the ``NAME_MISMATCHED`` argument using the new + signature. To avoid forcing the caller to require newer versions of CMake for + usage, the variable's value will be used if defined when the + ``NAME_MISMATCHED`` argument is not passed for the new signature (but using + both is an error).. + +Example for the full signature: + +.. code-block:: cmake + + find_package_handle_standard_args(LibArchive + REQUIRED_VARS LibArchive_LIBRARY LibArchive_INCLUDE_DIR + VERSION_VAR LibArchive_VERSION) + +In this case, the ``LibArchive`` package is considered to be found if +both ``LibArchive_LIBRARY`` and ``LibArchive_INCLUDE_DIR`` are valid. +Also the version of ``LibArchive`` will be checked by using the version +contained in ``LibArchive_VERSION``. Since no ``FAIL_MESSAGE`` is given, +the default messages will be printed. + +Another example for the full signature: + +.. code-block:: cmake + + find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4) + find_package_handle_standard_args(Automoc4 CONFIG_MODE) + +In this case, a ``FindAutmoc4.cmake`` module wraps a call to +``find_package(Automoc4 NO_MODULE)`` and adds an additional search +directory for ``automoc4``. Then the call to +``find_package_handle_standard_args`` produces a proper success/failure +message. + +.. command:: find_package_check_version + + .. versionadded:: 3.19 + + Helper function which can be used to check if a ``<version>`` is valid + against version-related arguments of :command:`find_package`. + + .. code-block:: cmake + + find_package_check_version(<version> <result-var> + [HANDLE_VERSION_RANGE] + [RESULT_MESSAGE_VARIABLE <message-var>] + ) + + The ``<result-var>`` will hold a boolean value giving the result of the check. + + The options are: + + ``HANDLE_VERSION_RANGE`` + Enable handling of a version range, if one is specified. Without this + option, a developer warning will be displayed if a version range is + specified. + + ``RESULT_MESSAGE_VARIABLE <message-var>`` + Specify a variable to get back a message describing the result of the check. + +Example for the usage: + +.. code-block:: cmake + + find_package_check_version(1.2.3 result HANDLE_VERSION_RANGE + RESULT_MESSAGE_VARIABLE reason) + if (result) + message (STATUS "${reason}") + else() + message (FATAL_ERROR "${reason}") + endif() +#]=======================================================================] + +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake) + + +cmake_policy(PUSH) +# numbers and boolean constants +cmake_policy (SET CMP0012 NEW) +# IN_LIST operator +cmake_policy (SET CMP0057 NEW) + + +# internal helper macro +macro(_FPHSA_FAILURE_MESSAGE _msg) + set (__msg "${_msg}") + if (FPHSA_REASON_FAILURE_MESSAGE) + string(APPEND __msg "\n Reason given by package: ${FPHSA_REASON_FAILURE_MESSAGE}\n") + endif() + if (${_NAME}_FIND_REQUIRED) + message(FATAL_ERROR "${__msg}") + else () + if (NOT ${_NAME}_FIND_QUIETLY) + message(STATUS "${__msg}") + endif () + endif () +endmacro() + + +# internal helper macro to generate the failure message when used in CONFIG_MODE: +macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE) + # <PackageName>_CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found: + if(${_NAME}_CONFIG) + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing:${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})") + else() + # If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version. + # List them all in the error message: + if(${_NAME}_CONSIDERED_CONFIGS) + set(configsText "") + list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount) + math(EXPR configsCount "${configsCount} - 1") + foreach(currentConfigIndex RANGE ${configsCount}) + list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename) + list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version) + string(APPEND configsText "\n ${filename} (version ${version})") + endforeach() + if (${_NAME}_NOT_FOUND_MESSAGE) + if (FPHSA_REASON_FAILURE_MESSAGE) + string(PREPEND FPHSA_REASON_FAILURE_MESSAGE "${${_NAME}_NOT_FOUND_MESSAGE}\n ") + else() + set(FPHSA_REASON_FAILURE_MESSAGE "${${_NAME}_NOT_FOUND_MESSAGE}") + endif() + else() + string(APPEND configsText "\n") + endif() + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:${configsText}") + + else() + # Simple case: No Config-file was found at all: + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}") + endif() + endif() +endmacro() + + +function(FIND_PACKAGE_CHECK_VERSION version result) + cmake_parse_arguments (PARSE_ARGV 2 FPCV "HANDLE_VERSION_RANGE;NO_AUTHOR_WARNING_VERSION_RANGE" "RESULT_MESSAGE_VARIABLE" "") + + if (FPCV_UNPARSED_ARGUMENTS) + message (FATAL_ERROR "find_package_check_version(): ${FPCV_UNPARSED_ARGUMENTS}: unexpected arguments") + endif() + if ("RESULT_MESSAGE_VARIABLE" IN_LIST FPCV_KEYWORDS_MISSING_VALUES) + message (FATAL_ERROR "find_package_check_version(): RESULT_MESSAGE_VARIABLE expects an argument") + endif() + + set (${result} FALSE PARENT_SCOPE) + if (FPCV_RESULT_MESSAGE_VARIABLE) + unset (${FPCV_RESULT_MESSAGE_VARIABLE} PARENT_SCOPE) + endif() + + if (_CMAKE_FPHSA_PACKAGE_NAME) + set (package "${_CMAKE_FPHSA_PACKAGE_NAME}") + elseif (CMAKE_FIND_PACKAGE_NAME) + set (package "${CMAKE_FIND_PACKAGE_NAME}") + else() + message (FATAL_ERROR "find_package_check_version(): Cannot be used outside a 'Find Module'") + endif() + + if (NOT FPCV_NO_AUTHOR_WARNING_VERSION_RANGE + AND ${package}_FIND_VERSION_RANGE AND NOT FPCV_HANDLE_VERSION_RANGE) + message(AUTHOR_WARNING + "`find_package()` specify a version range but the option " + "HANDLE_VERSION_RANGE` is not passed to `find_package_check_version()`. " + "Only the lower endpoint of the range will be used.") + endif() + + + set (version_ok FALSE) + unset (version_msg) + + if (FPCV_HANDLE_VERSION_RANGE AND ${package}_FIND_VERSION_RANGE) + if ((${package}_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" + AND version VERSION_GREATER_EQUAL ${package}_FIND_VERSION_MIN) + AND ((${package}_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" + AND version VERSION_LESS_EQUAL ${package}_FIND_VERSION_MAX) + OR (${package}_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" + AND version VERSION_LESS ${package}_FIND_VERSION_MAX))) + set (version_ok TRUE) + set(version_msg "(found suitable version \"${version}\", required range is \"${${package}_FIND_VERSION_RANGE}\")") + else() + set(version_msg "Found unsuitable version \"${version}\", required range is \"${${package}_FIND_VERSION_RANGE}\"") + endif() + elseif (DEFINED ${package}_FIND_VERSION) + if(${package}_FIND_VERSION_EXACT) # exact version required + # count the dots in the version string + string(REGEX REPLACE "[^.]" "" version_dots "${version}") + # add one dot because there is one dot more than there are components + string(LENGTH "${version_dots}." version_dots) + if (version_dots GREATER ${package}_FIND_VERSION_COUNT) + # Because of the C++ implementation of find_package() ${package}_FIND_VERSION_COUNT + # is at most 4 here. Therefore a simple lookup table is used. + if (${package}_FIND_VERSION_COUNT EQUAL 1) + set(version_regex "[^.]*") + elseif (${package}_FIND_VERSION_COUNT EQUAL 2) + set(version_regex "[^.]*\\.[^.]*") + elseif (${package}_FIND_VERSION_COUNT EQUAL 3) + set(version_regex "[^.]*\\.[^.]*\\.[^.]*") + else() + set(version_regex "[^.]*\\.[^.]*\\.[^.]*\\.[^.]*") + endif() + string(REGEX REPLACE "^(${version_regex})\\..*" "\\1" version_head "${version}") + if (NOT ${package}_FIND_VERSION VERSION_EQUAL version_head) + set(version_msg "Found unsuitable version \"${version}\", but required is exact version \"${${package}_FIND_VERSION}\"") + else () + set(version_ok TRUE) + set(version_msg "(found suitable exact version \"${_FOUND_VERSION}\")") + endif () + else () + if (NOT ${package}_FIND_VERSION VERSION_EQUAL version) + set(version_msg "Found unsuitable version \"${version}\", but required is exact version \"${${package}_FIND_VERSION}\"") + else () + set(version_ok TRUE) + set(version_msg "(found suitable exact version \"${version}\")") + endif () + endif () + else() # minimum version + if (${package}_FIND_VERSION VERSION_GREATER version) + set(version_msg "Found unsuitable version \"${version}\", but required is at least \"${${package}_FIND_VERSION}\"") + else() + set(version_ok TRUE) + set(version_msg "(found suitable version \"${version}\", minimum required is \"${${package}_FIND_VERSION}\")") + endif() + endif() + else () + set(version_ok TRUE) + set(version_msg "(found version \"${version}\")") + endif() + + set (${result} ${version_ok} PARENT_SCOPE) + if (FPCV_RESULT_MESSAGE_VARIABLE) + set (${FPCV_RESULT_MESSAGE_VARIABLE} "${version_msg}" PARENT_SCOPE) + endif() +endfunction() + + +function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG) + + # Set up the arguments for `cmake_parse_arguments`. + set(options CONFIG_MODE HANDLE_COMPONENTS NAME_MISMATCHED HANDLE_VERSION_RANGE) + set(oneValueArgs FAIL_MESSAGE REASON_FAILURE_MESSAGE VERSION_VAR FOUND_VAR) + set(multiValueArgs REQUIRED_VARS) + + # Check whether we are in 'simple' or 'extended' mode: + set(_KEYWORDS_FOR_EXTENDED_MODE ${options} ${oneValueArgs} ${multiValueArgs} ) + list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX) + + unset(FPHSA_NAME_MISMATCHED_override) + if (DEFINED FPHSA_NAME_MISMATCHED) + # If the variable NAME_MISMATCHED variable is set, error if it is passed as + # an argument. The former is for old signatures, the latter is for new + # signatures. + list(FIND ARGN "NAME_MISMATCHED" name_mismatched_idx) + if (NOT name_mismatched_idx EQUAL "-1") + message(FATAL_ERROR + "The `NAME_MISMATCHED` argument may only be specified by the argument or " + "the variable, not both.") + endif () + + # But use the variable if it is not an argument to avoid forcing minimum + # CMake version bumps for calling modules. + set(FPHSA_NAME_MISMATCHED_override "${FPHSA_NAME_MISMATCHED}") + endif () + + if(${INDEX} EQUAL -1) + set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG}) + set(FPHSA_REQUIRED_VARS ${ARGN}) + set(FPHSA_VERSION_VAR) + else() + cmake_parse_arguments(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN}) + + if(FPHSA_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"") + endif() + + if(NOT FPHSA_FAIL_MESSAGE) + set(FPHSA_FAIL_MESSAGE "DEFAULT_MSG") + endif() + + # In config-mode, we rely on the variable <PackageName>_CONFIG, which is set by find_package() + # when it successfully found the config-file, including version checking: + if(FPHSA_CONFIG_MODE) + list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG) + list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS) + set(FPHSA_VERSION_VAR ${_NAME}_VERSION) + endif() + + if(NOT FPHSA_REQUIRED_VARS AND NOT FPHSA_HANDLE_COMPONENTS) + message(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()") + endif() + endif() + + if (DEFINED FPHSA_NAME_MISMATCHED_override) + set(FPHSA_NAME_MISMATCHED "${FPHSA_NAME_MISMATCHED_override}") + endif () + + if (DEFINED CMAKE_FIND_PACKAGE_NAME + AND NOT FPHSA_NAME_MISMATCHED + AND NOT _NAME STREQUAL CMAKE_FIND_PACKAGE_NAME) + message(AUTHOR_WARNING + "The package name passed to `find_package_handle_standard_args` " + "(${_NAME}) does not match the name of the calling package " + "(${CMAKE_FIND_PACKAGE_NAME}). This can lead to problems in calling " + "code that expects `find_package` result variables (e.g., `_FOUND`) " + "to follow a certain pattern.") + endif () + + if (${_NAME}_FIND_VERSION_RANGE AND NOT FPHSA_HANDLE_VERSION_RANGE) + message(AUTHOR_WARNING + "`find_package()` specify a version range but the module ${_NAME} does " + "not support this capability. Only the lower endpoint of the range " + "will be used.") + endif() + + # to propagate package name to FIND_PACKAGE_CHECK_VERSION + set(_CMAKE_FPHSA_PACKAGE_NAME "${_NAME}") + + # now that we collected all arguments, process them + + if("x${FPHSA_FAIL_MESSAGE}" STREQUAL "xDEFAULT_MSG") + set(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}") + endif() + + if (FPHSA_REQUIRED_VARS) + list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR) + endif() + + string(TOUPPER ${_NAME} _NAME_UPPER) + string(TOLOWER ${_NAME} _NAME_LOWER) + + if(FPHSA_FOUND_VAR) + set(_FOUND_VAR_UPPER ${_NAME_UPPER}_FOUND) + set(_FOUND_VAR_MIXED ${_NAME}_FOUND) + if(FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_MIXED OR FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_UPPER) + set(_FOUND_VAR ${FPHSA_FOUND_VAR}) + else() + message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_FOUND_VAR_MIXED}\" and \"${_FOUND_VAR_UPPER}\" are valid names.") + endif() + else() + set(_FOUND_VAR ${_NAME_UPPER}_FOUND) + endif() + + # collect all variables which were not found, so they can be printed, so the + # user knows better what went wrong (#6375) + set(MISSING_VARS "") + set(DETAILS "") + # check if all passed variables are valid + set(FPHSA_FOUND_${_NAME} TRUE) + foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS}) + if(NOT ${_CURRENT_VAR}) + set(FPHSA_FOUND_${_NAME} FALSE) + string(APPEND MISSING_VARS " ${_CURRENT_VAR}") + else() + string(APPEND DETAILS "[${${_CURRENT_VAR}}]") + endif() + endforeach() + if(FPHSA_FOUND_${_NAME}) + set(${_NAME}_FOUND TRUE) + set(${_NAME_UPPER}_FOUND TRUE) + else() + set(${_NAME}_FOUND FALSE) + set(${_NAME_UPPER}_FOUND FALSE) + endif() + + # component handling + unset(FOUND_COMPONENTS_MSG) + unset(MISSING_COMPONENTS_MSG) + + if(FPHSA_HANDLE_COMPONENTS) + foreach(comp ${${_NAME}_FIND_COMPONENTS}) + if(${_NAME}_${comp}_FOUND) + + if(NOT DEFINED FOUND_COMPONENTS_MSG) + set(FOUND_COMPONENTS_MSG "found components:") + endif() + string(APPEND FOUND_COMPONENTS_MSG " ${comp}") + + else() + + if(NOT DEFINED MISSING_COMPONENTS_MSG) + set(MISSING_COMPONENTS_MSG "missing components:") + endif() + string(APPEND MISSING_COMPONENTS_MSG " ${comp}") + + if(${_NAME}_FIND_REQUIRED_${comp}) + set(${_NAME}_FOUND FALSE) + string(APPEND MISSING_VARS " ${comp}") + endif() + + endif() + endforeach() + set(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}") + string(APPEND DETAILS "[c${COMPONENT_MSG}]") + endif() + + # version handling: + set(VERSION_MSG "") + set(VERSION_OK TRUE) + + # check that the version variable is not empty to avoid emitting a misleading + # message (i.e. `Found unsuitable version ""`) + if (DEFINED ${_NAME}_FIND_VERSION) + if(DEFINED ${FPHSA_VERSION_VAR}) + if(NOT "${${FPHSA_VERSION_VAR}}" STREQUAL "") + set(_FOUND_VERSION ${${FPHSA_VERSION_VAR}}) + if (FPHSA_HANDLE_VERSION_RANGE) + set (FPCV_HANDLE_VERSION_RANGE HANDLE_VERSION_RANGE) + else() + set(FPCV_HANDLE_VERSION_RANGE NO_AUTHOR_WARNING_VERSION_RANGE) + endif() + find_package_check_version ("${_FOUND_VERSION}" VERSION_OK RESULT_MESSAGE_VARIABLE VERSION_MSG + ${FPCV_HANDLE_VERSION_RANGE}) + else() + set(VERSION_OK FALSE) + endif() + endif() + if("${${FPHSA_VERSION_VAR}}" STREQUAL "") + # if the package was not found, but a version was given, add that to the output: + if(${_NAME}_FIND_VERSION_EXACT) + set(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")") + elseif (FPHSA_HANDLE_VERSION_RANGE AND ${_NAME}_FIND_VERSION_RANGE) + set(VERSION_MSG "(Required is version range \"${${_NAME}_FIND_VERSION_RANGE}\")") + else() + set(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")") + endif() + endif() + else () + # Check with DEFINED as the found version may be 0. + if(DEFINED ${FPHSA_VERSION_VAR}) + set(VERSION_MSG "(found version \"${${FPHSA_VERSION_VAR}}\")") + endif() + endif () + + if(VERSION_OK) + string(APPEND DETAILS "[v${${FPHSA_VERSION_VAR}}(${${_NAME}_FIND_VERSION})]") + else() + set(${_NAME}_FOUND FALSE) + endif() + + + # print the result: + if (${_NAME}_FOUND) + FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}") + else () + + if(FPHSA_CONFIG_MODE) + _FPHSA_HANDLE_FAILURE_CONFIG_MODE() + else() + if(NOT VERSION_OK) + set(RESULT_MSG) + if (_FIRST_REQUIRED_VAR) + string (APPEND RESULT_MSG "found ${${_FIRST_REQUIRED_VAR}}") + endif() + if (COMPONENT_MSG) + if (RESULT_MSG) + string (APPEND RESULT_MSG ", ") + endif() + string (APPEND RESULT_MSG "${FOUND_COMPONENTS_MSG}") + endif() + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (${RESULT_MSG})") + else() + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing:${MISSING_VARS}) ${VERSION_MSG}") + endif() + endif() + + endif () + + set(${_NAME}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE) + set(${_NAME_UPPER}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE) +endfunction() + + +cmake_policy(POP) diff --git a/cmake/Modules/FindPackageMessage.cmake b/cmake/Modules/FindPackageMessage.cmake new file mode 100644 index 0000000..0628b98 --- /dev/null +++ b/cmake/Modules/FindPackageMessage.cmake @@ -0,0 +1,48 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +FindPackageMessage +------------------ + +.. code-block:: cmake + + find_package_message(<name> "message for user" "find result details") + +This function is intended to be used in FindXXX.cmake modules files. +It will print a message once for each unique find result. This is +useful for telling the user where a package was found. The first +argument specifies the name (XXX) of the package. The second argument +specifies the message to display. The third argument lists details +about the find result so that if they change the message will be +displayed again. The macro also obeys the QUIET argument to the +find_package command. + +Example: + +.. code-block:: cmake + + if(X11_FOUND) + find_package_message(X11 "Found X11: ${X11_X11_LIB}" + "[${X11_X11_LIB}][${X11_INCLUDE_DIR}]") + else() + ... + endif() +#]=======================================================================] + +function(find_package_message pkg msg details) + # Avoid printing a message repeatedly for the same find result. + if(NOT ${pkg}_FIND_QUIETLY) + string(REPLACE "\n" "" details "${details}") + set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg}) + if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}") + # The message has not yet been printed. + message(STATUS "${msg}") + + # Save the find details in the cache to avoid printing the same + # message again. + set("${DETAILS_VAR}" "${details}" + CACHE INTERNAL "Details about finding ${pkg}") + endif() + endif() +endfunction() diff --git a/cmake/Modules/FindPostgreSQL.cmake b/cmake/Modules/FindPostgreSQL.cmake new file mode 100644 index 0000000..84bc1ed --- /dev/null +++ b/cmake/Modules/FindPostgreSQL.cmake @@ -0,0 +1,315 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +FindPostgreSQL +-------------- + +Find the PostgreSQL installation. + +IMPORTED Targets +^^^^^^^^^^^^^^^^ + +.. versionadded:: 3.14 + +This module defines :prop_tgt:`IMPORTED` target ``PostgreSQL::PostgreSQL`` +if PostgreSQL has been found. + +Result Variables +^^^^^^^^^^^^^^^^ + +This module will set the following variables in your project: + +``PostgreSQL_FOUND`` + True if PostgreSQL is found. +``PostgreSQL_LIBRARIES`` + the PostgreSQL libraries needed for linking +``PostgreSQL_INCLUDE_DIRS`` + the directories of the PostgreSQL headers +``PostgreSQL_LIBRARY_DIRS`` + the link directories for PostgreSQL libraries +``PostgreSQL_VERSION_STRING`` + the version of PostgreSQL found +``PostgreSQL_TYPE_INCLUDE_DIR`` + the directories of the PostgreSQL server headers + +Components +^^^^^^^^^^ + +This module contains additional ``Server`` component, that forcibly checks +for the presence of server headers. Note that ``PostgreSQL_TYPE_INCLUDE_DIR`` +is set regardless of the presence of the ``Server`` component in find_package call. + +#]=======================================================================] + +# ---------------------------------------------------------------------------- +# History: +# This module is derived from the module originally found in the VTK source tree. +# +# ---------------------------------------------------------------------------- +# Note: +# PostgreSQL_ADDITIONAL_VERSIONS is a variable that can be used to set the +# version number of the implementation of PostgreSQL. +# In Windows the default installation of PostgreSQL uses that as part of the path. +# E.g C:\Program Files\PostgreSQL\8.4. +# Currently, the following version numbers are known to this module: +# "16" "15" "14" "13" "12" "11" "10" "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0" +# +# To use this variable just do something like this: +# set(PostgreSQL_ADDITIONAL_VERSIONS "9.2" "8.4.4") +# before calling find_package(PostgreSQL) in your CMakeLists.txt file. +# This will mean that the versions you set here will be found first in the order +# specified before the default ones are searched. +# +# ---------------------------------------------------------------------------- +# You may need to manually set: +# PostgreSQL_INCLUDE_DIR - the path to where the PostgreSQL include files are. +# PostgreSQL_LIBRARY_DIR - The path to where the PostgreSQL library files are. +# If FindPostgreSQL.cmake cannot find the include files or the library files. +# +# ---------------------------------------------------------------------------- +# The following variables are set if PostgreSQL is found: +# PostgreSQL_FOUND - Set to true when PostgreSQL is found. +# PostgreSQL_INCLUDE_DIRS - Include directories for PostgreSQL +# PostgreSQL_LIBRARY_DIRS - Link directories for PostgreSQL libraries +# PostgreSQL_LIBRARIES - The PostgreSQL libraries. +# +# The ``PostgreSQL::PostgreSQL`` imported target is also created. +# +# ---------------------------------------------------------------------------- +# If you have installed PostgreSQL in a non-standard location. +# (Please note that in the following comments, it is assumed that <Your Path> +# points to the root directory of the include directory of PostgreSQL.) +# Then you have three options. +# 1) After CMake runs, set PostgreSQL_INCLUDE_DIR to <Your Path>/include and +# PostgreSQL_LIBRARY_DIR to wherever the library pq (or libpq in windows) is +# 2) Use CMAKE_INCLUDE_PATH to set a path to <Your Path>/PostgreSQL<-version>. This will allow find_path() +# to locate PostgreSQL_INCLUDE_DIR by utilizing the PATH_SUFFIXES option. e.g. In your CMakeLists.txt file +# set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "<Your Path>/include") +# 3) Set an environment variable called ${PostgreSQL_ROOT} that points to the root of where you have +# installed PostgreSQL, e.g. <Your Path>. +# +# ---------------------------------------------------------------------------- + +cmake_policy(PUSH) +cmake_policy(SET CMP0057 NEW) # if IN_LIST + +set(PostgreSQL_INCLUDE_PATH_DESCRIPTION "top-level directory containing the PostgreSQL include directories. E.g /usr/local/include/PostgreSQL/8.4 or C:/Program Files/PostgreSQL/8.4/include") +set(PostgreSQL_INCLUDE_DIR_MESSAGE "Set the PostgreSQL_INCLUDE_DIR cmake cache entry to the ${PostgreSQL_INCLUDE_PATH_DESCRIPTION}") +set(PostgreSQL_LIBRARY_PATH_DESCRIPTION "top-level directory containing the PostgreSQL libraries.") +set(PostgreSQL_LIBRARY_DIR_MESSAGE "Set the PostgreSQL_LIBRARY_DIR cmake cache entry to the ${PostgreSQL_LIBRARY_PATH_DESCRIPTION}") +set(PostgreSQL_ROOT_DIR_MESSAGE "Set the PostgreSQL_ROOT system variable to where PostgreSQL is found on the machine E.g C:/Program Files/PostgreSQL/8.4") + + +set(PostgreSQL_KNOWN_VERSIONS ${PostgreSQL_ADDITIONAL_VERSIONS} + "16" "15" "14" "13" "12" "11" "10" "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0") + +# Define additional search paths for root directories. +set( PostgreSQL_ROOT_DIRECTORIES + ENV PostgreSQL_ROOT + ${PostgreSQL_ROOT} +) +foreach(suffix ${PostgreSQL_KNOWN_VERSIONS}) + if(WIN32) + list(APPEND PostgreSQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES + "PostgreSQL/${suffix}/lib") + list(APPEND PostgreSQL_INCLUDE_ADDITIONAL_SEARCH_SUFFIXES + "PostgreSQL/${suffix}/include") + list(APPEND PostgreSQL_TYPE_ADDITIONAL_SEARCH_SUFFIXES + "PostgreSQL/${suffix}/include/server") + endif() + if(UNIX) + list(APPEND PostgreSQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES + "postgresql${suffix}" + "postgresql@${suffix}" + "pgsql-${suffix}/lib") + list(APPEND PostgreSQL_INCLUDE_ADDITIONAL_SEARCH_SUFFIXES + "postgresql${suffix}" + "postgresql@${suffix}" + "postgresql/${suffix}" + "pgsql-${suffix}/include") + list(APPEND PostgreSQL_TYPE_ADDITIONAL_SEARCH_SUFFIXES + "postgresql${suffix}/server" + "postgresql@${suffix}/server" + "postgresql/${suffix}/server" + "pgsql-${suffix}/include/server") + endif() +endforeach() + +# +# Look for an installation. +# +find_path(PostgreSQL_INCLUDE_DIR + NAMES libpq-fe.h + PATHS + # Look in other places. + ${PostgreSQL_ROOT_DIRECTORIES} + PATH_SUFFIXES + pgsql + postgresql + include + ${PostgreSQL_INCLUDE_ADDITIONAL_SEARCH_SUFFIXES} + # Help the user find it if we cannot. + DOC "The ${PostgreSQL_INCLUDE_DIR_MESSAGE}" +) + +find_path(PostgreSQL_TYPE_INCLUDE_DIR + NAMES catalog/pg_type.h + PATHS + # Look in other places. + ${PostgreSQL_ROOT_DIRECTORIES} + PATH_SUFFIXES + postgresql + pgsql/server + postgresql/server + include/server + ${PostgreSQL_TYPE_ADDITIONAL_SEARCH_SUFFIXES} + # Help the user find it if we cannot. + DOC "The ${PostgreSQL_INCLUDE_DIR_MESSAGE}" +) + +# The PostgreSQL library. +set (PostgreSQL_LIBRARY_TO_FIND pq) +# Setting some more prefixes for the library +set (PostgreSQL_LIB_PREFIX "") +if ( WIN32 ) + set (PostgreSQL_LIB_PREFIX ${PostgreSQL_LIB_PREFIX} "lib") + set (PostgreSQL_LIBRARY_TO_FIND ${PostgreSQL_LIB_PREFIX}${PostgreSQL_LIBRARY_TO_FIND}) +endif() + +function(__postgresql_find_library _name) + find_library(${_name} + NAMES ${ARGN} + PATHS + ${PostgreSQL_ROOT_DIRECTORIES} + PATH_SUFFIXES + lib + ${PostgreSQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES} + # Help the user find it if we cannot. + DOC "The ${PostgreSQL_LIBRARY_DIR_MESSAGE}" + ) +endfunction() + +# For compatibility with versions prior to this multi-config search, honor +# any PostgreSQL_LIBRARY that is already specified and skip the search. +if(PostgreSQL_LIBRARY) + set(PostgreSQL_LIBRARIES "${PostgreSQL_LIBRARY}") + get_filename_component(PostgreSQL_LIBRARY_DIR "${PostgreSQL_LIBRARY}" PATH) +else() + __postgresql_find_library(PostgreSQL_LIBRARY_RELEASE ${PostgreSQL_LIBRARY_TO_FIND}) + __postgresql_find_library(PostgreSQL_LIBRARY_DEBUG ${PostgreSQL_LIBRARY_TO_FIND}d) + include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake) + select_library_configurations(PostgreSQL) + mark_as_advanced(PostgreSQL_LIBRARY_RELEASE PostgreSQL_LIBRARY_DEBUG) + if(PostgreSQL_LIBRARY_RELEASE) + get_filename_component(PostgreSQL_LIBRARY_DIR "${PostgreSQL_LIBRARY_RELEASE}" PATH) + elseif(PostgreSQL_LIBRARY_DEBUG) + get_filename_component(PostgreSQL_LIBRARY_DIR "${PostgreSQL_LIBRARY_DEBUG}" PATH) + else() + set(PostgreSQL_LIBRARY_DIR "") + endif() +endif() + +if (PostgreSQL_INCLUDE_DIR) + # Some platforms include multiple pg_config.hs for multi-lib configurations + # This is a temporary workaround. A better solution would be to compile + # a dummy c file and extract the value of the symbol. + file(GLOB _PG_CONFIG_HEADERS "${PostgreSQL_INCLUDE_DIR}/pg_config*.h") + foreach(_PG_CONFIG_HEADER ${_PG_CONFIG_HEADERS}) + if(EXISTS "${_PG_CONFIG_HEADER}") + file(STRINGS "${_PG_CONFIG_HEADER}" pgsql_version_str + REGEX "^#define[\t ]+PG_VERSION_NUM[\t ]+.*") + if(pgsql_version_str) + string(REGEX REPLACE "^#define[\t ]+PG_VERSION_NUM[\t ]+([0-9]*).*" + "\\1" _PostgreSQL_VERSION_NUM "${pgsql_version_str}") + break() + endif() + endif() + endforeach() + if (_PostgreSQL_VERSION_NUM) + # 9.x and older encoding + if (_PostgreSQL_VERSION_NUM LESS 100000) + math(EXPR _PostgreSQL_major_version "${_PostgreSQL_VERSION_NUM} / 10000") + math(EXPR _PostgreSQL_minor_version "${_PostgreSQL_VERSION_NUM} % 10000 / 100") + math(EXPR _PostgreSQL_patch_version "${_PostgreSQL_VERSION_NUM} % 100") + set(PostgreSQL_VERSION_STRING "${_PostgreSQL_major_version}.${_PostgreSQL_minor_version}.${_PostgreSQL_patch_version}") + unset(_PostgreSQL_major_version) + unset(_PostgreSQL_minor_version) + unset(_PostgreSQL_patch_version) + else () + math(EXPR _PostgreSQL_major_version "${_PostgreSQL_VERSION_NUM} / 10000") + math(EXPR _PostgreSQL_minor_version "${_PostgreSQL_VERSION_NUM} % 10000") + set(PostgreSQL_VERSION_STRING "${_PostgreSQL_major_version}.${_PostgreSQL_minor_version}") + unset(_PostgreSQL_major_version) + unset(_PostgreSQL_minor_version) + endif () + else () + foreach(_PG_CONFIG_HEADER ${_PG_CONFIG_HEADERS}) + if(EXISTS "${_PG_CONFIG_HEADER}") + file(STRINGS "${_PG_CONFIG_HEADER}" pgsql_version_str + REGEX "^#define[\t ]+PG_VERSION[\t ]+\".*\"") + if(pgsql_version_str) + string(REGEX REPLACE "^#define[\t ]+PG_VERSION[\t ]+\"([^\"]*)\".*" + "\\1" PostgreSQL_VERSION_STRING "${pgsql_version_str}") + break() + endif() + endif() + endforeach() + endif () + unset(_PostgreSQL_VERSION_NUM) + unset(pgsql_version_str) +endif() + +if("Server" IN_LIST PostgreSQL_FIND_COMPONENTS) + set(PostgreSQL_Server_FOUND TRUE) + if(NOT PostgreSQL_TYPE_INCLUDE_DIR) + set(PostgreSQL_Server_FOUND FALSE) + endif() +endif() + +# Did we find anything? +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) +find_package_handle_standard_args(PostgreSQL + REQUIRED_VARS PostgreSQL_LIBRARY PostgreSQL_INCLUDE_DIR + HANDLE_COMPONENTS + VERSION_VAR PostgreSQL_VERSION_STRING) +set(PostgreSQL_FOUND ${POSTGRESQL_FOUND}) + +function(__postgresql_import_library _target _var _config) + if(_config) + set(_config_suffix "_${_config}") + else() + set(_config_suffix "") + endif() + + set(_lib "${${_var}${_config_suffix}}") + if(EXISTS "${_lib}") + if(_config) + set_property(TARGET ${_target} APPEND PROPERTY + IMPORTED_CONFIGURATIONS ${_config}) + endif() + set_target_properties(${_target} PROPERTIES + IMPORTED_LOCATION${_config_suffix} "${_lib}") + endif() +endfunction() + +# Now try to get the include and library path. +if(PostgreSQL_FOUND) + set(PostgreSQL_INCLUDE_DIRS ${PostgreSQL_INCLUDE_DIR}) + if(PostgreSQL_TYPE_INCLUDE_DIR) + list(APPEND PostgreSQL_INCLUDE_DIRS ${PostgreSQL_TYPE_INCLUDE_DIR}) + endif() + set(PostgreSQL_LIBRARY_DIRS ${PostgreSQL_LIBRARY_DIR}) + if (NOT TARGET PostgreSQL::PostgreSQL) + add_library(PostgreSQL::PostgreSQL UNKNOWN IMPORTED) + set_target_properties(PostgreSQL::PostgreSQL PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${PostgreSQL_INCLUDE_DIRS}") + __postgresql_import_library(PostgreSQL::PostgreSQL PostgreSQL_LIBRARY "") + __postgresql_import_library(PostgreSQL::PostgreSQL PostgreSQL_LIBRARY "RELEASE") + __postgresql_import_library(PostgreSQL::PostgreSQL PostgreSQL_LIBRARY "DEBUG") + endif () +endif() + +mark_as_advanced(PostgreSQL_INCLUDE_DIR PostgreSQL_TYPE_INCLUDE_DIR) + +cmake_policy(POP) diff --git a/cmake/Modules/SelectLibraryConfigurations.cmake b/cmake/Modules/SelectLibraryConfigurations.cmake new file mode 100644 index 0000000..4c0e9a8 --- /dev/null +++ b/cmake/Modules/SelectLibraryConfigurations.cmake @@ -0,0 +1,80 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +SelectLibraryConfigurations +--------------------------- + +.. code-block:: cmake + + select_library_configurations(basename) + +This macro takes a library base name as an argument, and will choose +good values for the variables + +:: + + basename_LIBRARY + basename_LIBRARIES + basename_LIBRARY_DEBUG + basename_LIBRARY_RELEASE + +depending on what has been found and set. + +If only ``basename_LIBRARY_RELEASE`` is defined, ``basename_LIBRARY`` will +be set to the release value, and ``basename_LIBRARY_DEBUG`` will be set +to ``basename_LIBRARY_DEBUG-NOTFOUND``. If only ``basename_LIBRARY_DEBUG`` +is defined, then ``basename_LIBRARY`` will take the debug value, and +``basename_LIBRARY_RELEASE`` will be set to ``basename_LIBRARY_RELEASE-NOTFOUND``. + +If the generator supports configuration types, then ``basename_LIBRARY`` +and ``basename_LIBRARIES`` will be set with debug and optimized flags +specifying the library to be used for the given configuration. If no +build type has been set or the generator in use does not support +configuration types, then ``basename_LIBRARY`` and ``basename_LIBRARIES`` +will take only the release value, or the debug value if the release one +is not set. +#]=======================================================================] + +# This macro was adapted from the FindQt4 CMake module and is maintained by Will +# Dicharry <wdicharry@stellarscience.com>. + +macro(select_library_configurations basename) + if(NOT ${basename}_LIBRARY_RELEASE) + set(${basename}_LIBRARY_RELEASE "${basename}_LIBRARY_RELEASE-NOTFOUND" CACHE FILEPATH "Path to a library.") + endif() + if(NOT ${basename}_LIBRARY_DEBUG) + set(${basename}_LIBRARY_DEBUG "${basename}_LIBRARY_DEBUG-NOTFOUND" CACHE FILEPATH "Path to a library.") + endif() + + get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if( ${basename}_LIBRARY_DEBUG AND ${basename}_LIBRARY_RELEASE AND + NOT ${basename}_LIBRARY_DEBUG STREQUAL ${basename}_LIBRARY_RELEASE AND + ( _isMultiConfig OR CMAKE_BUILD_TYPE ) ) + # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for + # single-config generators, set optimized and debug libraries + set( ${basename}_LIBRARY "" ) + foreach( _libname IN LISTS ${basename}_LIBRARY_RELEASE ) + list( APPEND ${basename}_LIBRARY optimized "${_libname}" ) + endforeach() + foreach( _libname IN LISTS ${basename}_LIBRARY_DEBUG ) + list( APPEND ${basename}_LIBRARY debug "${_libname}" ) + endforeach() + elseif( ${basename}_LIBRARY_RELEASE ) + set( ${basename}_LIBRARY ${${basename}_LIBRARY_RELEASE} ) + elseif( ${basename}_LIBRARY_DEBUG ) + set( ${basename}_LIBRARY ${${basename}_LIBRARY_DEBUG} ) + else() + set( ${basename}_LIBRARY "${basename}_LIBRARY-NOTFOUND") + endif() + + set( ${basename}_LIBRARIES "${${basename}_LIBRARY}" ) + + if( ${basename}_LIBRARY ) + set( ${basename}_FOUND TRUE ) + endif() + + mark_as_advanced( ${basename}_LIBRARY_RELEASE + ${basename}_LIBRARY_DEBUG + ) +endmacro() diff --git a/include/connection.h b/include/connection.h index e67ea27..cf3fb2e 100644 --- a/include/connection.h +++ b/include/connection.h @@ -19,8 +19,8 @@ */ -#ifndef CONNECTION_H -#define CONNECTION_H +#ifndef CSSQLDB_CONNECTION_H +#define CSSQLDB_CONNECTION_H #include <plugin.h> #include "logindata.h" @@ -68,7 +68,7 @@ struct ConnectionData { void Close(csnd::Csound* csound); void Exec(char* sql); MYFLT Scalar(char* sql, int row, int col); - char* ScalarString(char* sql, int row=0, int col=0); + char* ScalarString(char* sql, csnd::Csound* csound, int row=0, int col=0); void ArrayQuery(char* sql, csnd::Csound* csound, ARRAYDAT* array); void ArrayQueryString(char* sql, csnd::Csound* csound, ARRAYDAT* array); }; diff --git a/include/logindata.h b/include/logindata.h index 8a62e6b..be8e79a 100644 --- a/include/logindata.h +++ b/include/logindata.h @@ -19,8 +19,8 @@ */ -#ifndef LOGINDATA_H -#define LOGINDATA_H +#ifndef CSSQLDB_LOGINDATA_H +#define CSSQLDB_LOGINDATA_H struct LoginData { int dbType; diff --git a/include/mysql.h b/include/mysql.h index 1abc6e3..950e9d3 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -19,8 +19,8 @@ */ -#ifndef MYSQL_H -#define MYSQL_H +#ifndef CSSQLDB_MYSQL_H +#define CSSQLDB_MYSQL_H #include <plugin.h> #include <cppconn/driver.h> @@ -37,7 +37,7 @@ struct MySQLConnection { void Exec(char* sql); mysql::ResultSet* Query(char *sql); MYFLT Scalar(char* sql, int row, int col); - char* ScalarString(char* sql, int row, int col); + char* ScalarString(char* sql, csnd::Csound* csound, int row, int col); void ToArray(mysql::ResultSet* result, csnd::Csound* csound, ARRAYDAT* array, bool asString); void ArrayQuery(char* sql, csnd::Csound* csound, ARRAYDAT* array); void ArrayQueryString(char* sql, csnd::Csound* csound, ARRAYDAT* array); diff --git a/include/postgresql.h b/include/postgresql.h index d7db5d9..eaf01c8 100644 --- a/include/postgresql.h +++ b/include/postgresql.h @@ -19,22 +19,22 @@ */ -#ifndef POSTGRESQL_H -#define POSTGRESQL_H +#ifndef CSSQLDB_POSTGRESQL_H +#define CSSQLDB_POSTGRESQL_H #include <plugin.h> -#include <pqxx/pqxx> +#include "libpq-fe.h" #include "connection.h" struct PostgresConnection { - pqxx::connection* conn; + PGconn* conn; void Init(csnd::Csound* csound, LoginData* login); void Close(csnd::Csound* csound); void Exec(char* sql); - pqxx::result Query(char *sql); + PGresult* Query(char *sql); MYFLT Scalar(char* sql, int row, int col); - char* ScalarString(char* sql, int row, int col); - void ToArray(pqxx::result result, csnd::Csound* csound, ARRAYDAT* array, bool asString); + char* ScalarString(char* sql, csnd::Csound* csound, int row, int col); + void ToArray(PGresult* result, csnd::Csound* csound, ARRAYDAT* array, bool asString); void ArrayQuery(char* sql, csnd::Csound* csound, ARRAYDAT* array); void ArrayQueryString(char* sql, csnd::Csound* csound, ARRAYDAT* array); }; diff --git a/include/sqlite.h b/include/sqlite.h index 4e2b0c3..c42eb57 100644 --- a/include/sqlite.h +++ b/include/sqlite.h @@ -19,8 +19,8 @@ */ -#ifndef XSQLITE3_H -#define XSQLITE3_H +#ifndef CSSQLDB_SQLITE3_H +#define CSSQLDB_SQLITE3_H #include <plugin.h> #include <sqlite3.h> @@ -33,7 +33,7 @@ struct SqliteConnection { void Exec(char* sql); sqlite3_stmt* Query(char *sql); MYFLT Scalar(char* sql, int row, int col); - char* ScalarString(char* sql, int row, int col); + char* ScalarString(char* sql, csnd::Csound* csound, int row, int col); int RowCount(sqlite3_stmt* stmt); void ToArray(sqlite3_stmt* result, csnd::Csound* csound, ARRAYDAT* array, bool asString); void ArrayQuery(char* sql, csnd::Csound* csound, ARRAYDAT* array); diff --git a/include/tools.h b/include/tools.h new file mode 100644 index 0000000..54a0363 --- /dev/null +++ b/include/tools.h @@ -0,0 +1,30 @@ +/* + tools.h + Copyright (C) 2022 Richard Knight + + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + */ + +#ifndef CSSQLDB_TOOLS_H +#define CSSQLDB_TOOLS_H + +#include <plugin.h> + +STRINGDAT* arrayInit(csnd::Csound* csound, ARRAYDAT* array, int rows, int cols); +void insertArrayStringItem(csnd::Csound* csound, STRINGDAT* strings, int index, char* item); + +#endif /* TOOLS_H */ diff --git a/src/connection.cpp b/src/connection.cpp index 5ac0aa1..43175bd 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -109,7 +109,7 @@ void ConnectionData::Exec(char* sql) { } } -MYFLT ConnectionData::Scalar(char* sql, int row=0, int col=0) { +MYFLT ConnectionData::Scalar(char* sql, int row, int col) { if (!open) { throw std::runtime_error(badConnection); } @@ -136,7 +136,7 @@ MYFLT ConnectionData::Scalar(char* sql, int row=0, int col=0) { } -char* ConnectionData::ScalarString(char* sql, int row=0, int col=0) { +char* ConnectionData::ScalarString(char* sql, csnd::Csound* csound, int row, int col) { if (!open) { throw std::runtime_error(badConnection); } @@ -144,17 +144,17 @@ char* ConnectionData::ScalarString(char* sql, int row=0, int col=0) { switch (type) { #ifdef BUILD_POSTGRES case POSTGRES: - return postgres->ScalarString(sql, row, col); + return postgres->ScalarString(sql, csound, row, col); break; #endif #ifdef BUILD_SQLITE case SQLITE: - return sqlite->ScalarString(sql, row, col); + return sqlite->ScalarString(sql, csound, row, col); break; #endif #ifdef BUILD_MYSQL case MYSQL: - return mysql->ScalarString(sql, row, col); + return mysql->ScalarString(sql, csound, row, col); break; #endif default: diff --git a/src/mysql.cpp b/src/mysql.cpp index 040670e..381898b 100644 --- a/src/mysql.cpp +++ b/src/mysql.cpp @@ -20,6 +20,7 @@ */ #include <plugin.h> +#include "tools.h" #include <iostream> #include <cppconn/driver.h> #include <cppconn/exception.h> @@ -62,11 +63,12 @@ mysql::ResultSet* MySQLConnection::Query(char* sql) { return result; } -MYFLT MySQLConnection::Scalar(char* sql, int row=0, int col=0) { +MYFLT MySQLConnection::Scalar(char* sql, int row, int col) { mysql::ResultSet* res = Query(sql); mysql::ResultSetMetaData* meta = res->getMetaData(); int colCount = meta->getColumnCount(); if (col > colCount - 1) { + delete res; throw std::runtime_error("column number out of range"); } @@ -78,12 +80,13 @@ MYFLT MySQLConnection::Scalar(char* sql, int row=0, int col=0) { return result; } -char* MySQLConnection::ScalarString(char* sql, int row=0, int col=0) { +char* MySQLConnection::ScalarString(char* sql, csnd::Csound* csound, int row, int col) { mysql::ResultSet* res = Query(sql); mysql::ResultSetMetaData* meta = res->getMetaData(); int colCount = meta->getColumnCount(); if (col > colCount - 1) { + delete res; throw std::runtime_error("column number out of range"); } @@ -91,7 +94,7 @@ char* MySQLConnection::ScalarString(char* sql, int row=0, int col=0) { for (int rowIndex = 0; rowIndex <= row; rowIndex++) { res->next(); } - char* result = res->getString(col + 1).c_str(); + char* result = csound->strdup((char*) res->getString(col + 1).c_str()); delete res; @@ -101,31 +104,18 @@ char* MySQLConnection::ScalarString(char* sql, int row=0, int col=0) { void MySQLConnection::ToArray(mysql::ResultSet* result, csnd::Csound* csound, ARRAYDAT* array, bool asString) { mysql::ResultSetMetaData* meta = result->getMetaData(); - int colNum = meta->getColumnCount(); - int rowNum = result->rowsCount(); - int totalResults = colNum * rowNum; - array->sizes = csound->calloc(sizeof(int32_t) * 2); - array->sizes[0] = rowNum; - array->sizes[1] = colNum; - array->dimensions = 2; - CS_VARIABLE *var = array->arrayType->createVariable(csound, NULL); - array->arrayMemberSize = var->memBlockSize; - array->data = csound->calloc(var->memBlockSize * totalResults); - STRINGDAT* strings; - if (asString) { - strings = (STRINGDAT*) array->data; - } + int cols = meta->getColumnCount(); + int rows = result->rowsCount(); + STRINGDAT* strings = arrayInit(csound, array, rows, cols); int colIndex; int index = 0; while (result->next()) { colIndex = 0; - while (colIndex < colNum) { + while (colIndex < cols) { if (asString) { - char* item = result->getString(colIndex + 1).c_str(); - strings[index].size = strlen(item) + 1; - strings[index].data = csound->strdup(item); + insertArrayStringItem(csound, strings, index, (char*) result->getString(colIndex + 1).c_str()); } else { array->data[index] = (MYFLT) result->getDouble(colIndex + 1); } diff --git a/src/opcodes.cpp b/src/opcodes.cpp index 3527f83..1a6a333 100644 --- a/src/opcodes.cpp +++ b/src/opcodes.cpp @@ -95,11 +95,11 @@ public: try { switch (queryData->queryType) { case SCALARSTRING: { - std::string resultString = connection->ScalarString(queryData->sql, queryData->row, queryData->col); + std::string resultString = connection->ScalarString(queryData->sql, csound, queryData->row, queryData->col); if (charData != NULL) { csound->free(charData); } - charData = csound->strdup(resultString.c_str()); + charData = csound->strdup((char*) resultString.c_str()); charSize = resultString.length() + 1; } break; @@ -128,7 +128,7 @@ public: status = 1; done = true; pending = false; - error = csound->strdup(e.what()); + error = csound->strdup((char*) e.what()); } UNLOCK(connection); } @@ -440,12 +440,12 @@ struct dbexec : csnd::InPlug<2> { LOCK(connection); try { connection->Exec(sql.data); - return OK; } catch (const std::exception &e) { + UNLOCK(connection); return csound->init_error(e.what()); } UNLOCK(connection); - + return OK; } }; @@ -461,14 +461,15 @@ struct dbscalar : csnd::Plugin<1, 4> { return csound->init_error(badHandle); } STRINGDAT &sql = inargs.str_data(1); + LOCK(connection); try { - LOCK(connection); outargs[0] = connection->Scalar(sql.data, inargs[2], inargs[3]); - UNLOCK(connection); - return OK; } catch (const std::exception &e) { + UNLOCK(connection); return csound->init_error(e.what()); - } + } + UNLOCK(connection) + return OK; } }; @@ -479,6 +480,7 @@ struct dbscalarstr : csnd::Plugin<1, 4> { static constexpr char const *otypes = "S"; static constexpr char const *itypes = "iSoo"; ConnectionData* connection; + char* resultString; int init() { if (!(connection = getConnection(csound, inargs[0]))) { @@ -486,16 +488,20 @@ struct dbscalarstr : csnd::Plugin<1, 4> { } STRINGDAT &sql = inargs.str_data(1); STRINGDAT &result = outargs.str_data(0); + LOCK(connection); try { - LOCK(connection); - std::string resultString = connection->ScalarString(sql.data, inargs[2], inargs[3]); - UNLOCK(connection); - result.size = resultString.length() + 1; - result.data = csound->strdup(resultString.c_str()); - return OK; + if (resultString != NULL) { + csound->free(resultString); + } + resultString = connection->ScalarString(sql.data, csound, inargs[2], inargs[3]); + result.size = strlen(resultString) + 1; + result.data = csound->strdup(resultString); } catch (const std::exception &e) { + UNLOCK(connection); return csound->init_error(e.what()); - } + } + UNLOCK(connection); + return OK; } }; @@ -516,15 +522,15 @@ struct dbarray : csnd::Plugin<1, 2> { STRINGDAT &sql = inargs.str_data(1); ARRAYDAT* array = (ARRAYDAT*) outargs(0); - + LOCK(connection); try { - LOCK(connection); connection->ArrayQuery(sql.data, csound, array); - UNLOCK(connection); - return OK; } catch (const std::exception &e) { + UNLOCK(connection); return csound->init_error(e.what()); } + UNLOCK(connection); + return OK; } }; @@ -544,15 +550,15 @@ struct dbarraystr : csnd::Plugin<1, 2> { STRINGDAT &sql = inargs.str_data(1); ARRAYDAT* array = (ARRAYDAT*) outargs(0); - + LOCK(connection); try { - LOCK(connection); connection->ArrayQueryString(sql.data, csound, array); - UNLOCK(connection); - return OK; } catch (const std::exception &e) { + UNLOCK(connection); return csound->init_error(e.what()); } + UNLOCK(connection); + return OK; } }; @@ -579,14 +585,15 @@ struct dbexec_kb : csnd::InPlug<2> { int kperf() { STRINGDAT &sql = args.str_data(1); + LOCK(connection); try { - LOCK(connection); connection->Exec(sql.data); - UNLOCK(connection); - return OK; } catch (const std::exception &e) { + UNLOCK(connection); return csound->perf_error(e.what(), this); } + UNLOCK(connection); + return OK; } }; @@ -606,14 +613,15 @@ struct dbscalar_kb : csnd::Plugin<1, 4> { int kperf() { STRINGDAT &sql = inargs.str_data(1); + LOCK(connection); try { - LOCK(connection); outargs[0] = connection->Scalar(sql.data, inargs[2], inargs[3]); - UNLOCK(connection); - return OK; } catch (const std::exception &e) { + UNLOCK(connection); return csound->perf_error(e.what(), this); } + UNLOCK(connection); + return OK; } }; @@ -636,16 +644,17 @@ struct dbscalarstr_kb : csnd::Plugin<1, 4> { STRINGDAT &sql = inargs.str_data(1); STRINGDAT &result = outargs.str_data(0); + LOCK(connection); try { - LOCK(connection); - std::string resultString = connection->ScalarString(sql.data, inargs[2], inargs[3]); - UNLOCK(connection); - result.size = resultString.length() + 1; - result.data = csound->strdup(resultString.c_str()); - return OK; + char* resultString = connection->ScalarString(sql.data, csound, inargs[2], inargs[3]); + result.size = strlen(resultString) + 1; + result.data = resultString; } catch (const std::exception &e) { + UNLOCK(connection); return csound->perf_error(e.what(), this); } + UNLOCK(connection); + return OK; } }; @@ -670,15 +679,15 @@ struct dbarray_kb : csnd::Plugin<1, 2> { STRINGDAT &sql = inargs.str_data(1); ARRAYDAT* array = (ARRAYDAT*) outargs(0); - + LOCK(connection); try { - LOCK(connection); connection->ArrayQuery(sql.data, csound, array); - UNLOCK(connection); - return OK; } catch (const std::exception &e) { + UNLOCK(connection); return csound->perf_error(e.what(), this); } + UNLOCK(connection); + return OK; } }; @@ -702,15 +711,15 @@ struct dbarraystr_kb : csnd::Plugin<1, 2> { STRINGDAT &sql = inargs.str_data(1); ARRAYDAT* array = (ARRAYDAT*) outargs(0); - + LOCK(connection); try { - LOCK(connection); connection->ArrayQueryString(sql.data, csound, array); - UNLOCK(connection); - return OK; } catch (const std::exception &e) { + UNLOCK(connection); return csound->perf_error(e.what(), this); } + UNLOCK(connection); + return OK; } }; @@ -746,4 +755,4 @@ void csnd::on_load(csnd::Csound *csound) { csnd::plugin<dbarray_kb>(csound, "dbarray_kb", csnd::thread::ik); csnd::plugin<dbarraystr_kb>(csound, "dbarray_kb.S", csnd::thread::ik); -}
\ No newline at end of file +} diff --git a/src/postgresql.cpp b/src/postgresql.cpp index 681c133..7e194c6 100644 --- a/src/postgresql.cpp +++ b/src/postgresql.cpp @@ -20,15 +20,14 @@ */ #include <plugin.h> +#include "tools.h" #include <iostream> -#include <pqxx/pqxx> +#include "libpq-fe.h" #include "connection.h" #include "postgresql.h" - void PostgresConnection::Init(csnd::Csound* csound, LoginData* login) { - //conn = (pqxx::connection*) csound->malloc(sizeof(pqxx::connection)); char connectionString[256]; snprintf(connectionString, 256, @@ -36,90 +35,85 @@ void PostgresConnection::Init(csnd::Csound* csound, LoginData* login) { login->dbName, login->dbUser, login->dbPass, login->dbHost ); - conn = new pqxx::connection(connectionString); + conn = PQconnectdb(connectionString); - if (!conn->is_open()) { + if (PQstatus(conn) == CONNECTION_BAD) { throw std::runtime_error("Connection not open"); } } void PostgresConnection::Close(csnd::Csound* csound) { - if (conn->is_open()) { - conn->disconnect(); - } - delete conn; + PQfinish(conn); } void PostgresConnection::Exec(char* sql) { - pqxx::nontransaction nt(*conn); - nt.exec(sql); + PGresult* result = PQexec(conn, sql); + PQclear(result); } -pqxx::result PostgresConnection::Query(char* sql) { - pqxx::nontransaction nt(*conn); - pqxx::result result(nt.exec(sql)); - return result; +PGresult* PostgresConnection::Query(char* sql) { + return PQexec(conn, sql); } -MYFLT PostgresConnection::Scalar(char* sql, int row=0, int col=0) { - pqxx::result result = Query(sql); +MYFLT PostgresConnection::Scalar(char* sql, int row, int col) { + PGresult* result = Query(sql); - // checks as libpqxx not throwing if this happens - if (row > result.size() - 1) { + int rows = PQntuples(result); + int cols = PQnfields(result); + + if (row > rows - 1) { + PQclear(result); throw std::runtime_error("row number out of range"); } - if (col > result[row].size() -1) { + if (col > cols - 1) { + PQclear(result); throw std::runtime_error("column number out of range"); } - return result[row][col].as<MYFLT>(); + MYFLT value = (MYFLT) atof(PQgetvalue(result, row, col)); + PQclear(result); + return value; } -char* PostgresConnection::ScalarString(char* sql, int row=0, int col=0) { - pqxx::result result = Query(sql); +char* PostgresConnection::ScalarString(char* sql, csnd::Csound* csound, int row, int col) { + PGresult* result = Query(sql); - // checks as libpqxx not throwing if this happens - if (row > result.size() - 1) { + int rows = PQntuples(result); + int cols = PQnfields(result); + + if (row > rows - 1) { + PQclear(result); throw std::runtime_error("row number out of range"); } - if (col > result[row].size() -1) { + if (col > cols -1) { + PQclear(result); throw std::runtime_error("column number out of range"); } - return result[row][col].c_str(); + char* value = csound->strdup(PQgetvalue(result, row, col)); + PQclear(result); + return value; } -void PostgresConnection::ToArray(pqxx::result result, csnd::Csound* csound, ARRAYDAT* array, bool asString) { - int totalResults = result.size() * result[0].size(); - array->sizes = csound->calloc(sizeof(int32_t) * 2); - array->sizes[0] = result.size(); - array->sizes[1] = result[0].size(); - array->dimensions = 2; - CS_VARIABLE *var = array->arrayType->createVariable(csound, NULL); - array->arrayMemberSize = var->memBlockSize; - array->data = csound->calloc(var->memBlockSize * totalResults); - STRINGDAT* strings; - if (asString) { - strings = (STRINGDAT*) array->data; - } +void PostgresConnection::ToArray(PGresult* result, csnd::Csound* csound, ARRAYDAT* array, bool asString) { + int rows = PQntuples(result); + int cols = PQnfields(result); + STRINGDAT* strings = arrayInit(csound, array, rows, cols); int index = 0; - for (int rowNum = 0; rowNum < result.size(); ++rowNum) { - const pqxx::row row = result[rowNum]; - for (int colNum = 0; colNum < row.size(); ++colNum) { - const pqxx::field field = row[colNum]; + for (int rowIndex = 0; rowIndex < rows; ++rowIndex) { + for (int colIndex = 0; colIndex < cols; ++colIndex) { if (asString) { - char* item = field.c_str(); - strings[index].size = strlen(item) + 1; - strings[index].data = csound->strdup(item); + insertArrayStringItem(csound, strings, index, (char*) PQgetvalue(result, rowIndex, colIndex)); } else { - array->data[index] = field.as<MYFLT>(); + array->data[index] = (MYFLT) atof(PQgetvalue(result, rowIndex, colIndex)); } index++; } } + PQclear(result); } void PostgresConnection::ArrayQueryString(char* sql, csnd::Csound* csound, ARRAYDAT* array) { diff --git a/src/sqlite3.cpp b/src/sqlite3.cpp index 824e165..cbd4af1 100644 --- a/src/sqlite3.cpp +++ b/src/sqlite3.cpp @@ -20,6 +20,7 @@ */ #include <plugin.h> +#include "tools.h" #include <iostream> #include <sqlite3.h> #include "connection.h" @@ -28,7 +29,6 @@ void SqliteConnection::Init(csnd::Csound* csound, LoginData* login) { int result = sqlite3_open(login->dbName, &conn); - std::cout << "Y"; if (result) { throw std::runtime_error("connection not established"); } @@ -53,18 +53,20 @@ sqlite3_stmt* SqliteConnection::Query(char* sql) { return stmt; } -MYFLT SqliteConnection::Scalar(char* sql, int row=0, int col=0) { +MYFLT SqliteConnection::Scalar(char* sql, int row, int col) { sqlite3_stmt *stmt = Query(sql); int colCount = sqlite3_column_count(stmt); int rc = sqlite3_step(stmt); + + if (col > colCount -1) { + rc = sqlite3_finalize(stmt); + throw std::runtime_error("column number out of range"); + } + + rc = sqlite3_step(stmt); int rowIndex = 0; while (rc != SQLITE_DONE && rc != SQLITE_OK) { if (rowIndex == row) { - - if (col > colCount -1) { - rc = sqlite3_finalize(stmt); - throw std::runtime_error("column number out of range"); - } MYFLT result = (MYFLT) sqlite3_column_double(stmt, col); rc = sqlite3_finalize(stmt); return result; @@ -76,7 +78,7 @@ MYFLT SqliteConnection::Scalar(char* sql, int row=0, int col=0) { throw std::runtime_error("no result"); } -char* SqliteConnection::ScalarString(char* sql, int row=0, int col=0) { +char* SqliteConnection::ScalarString(char* sql, csnd::Csound* csound, int row, int col) { sqlite3_stmt *stmt = Query(sql); int colCount = sqlite3_column_count(stmt); int rc = sqlite3_step(stmt); @@ -88,7 +90,7 @@ char* SqliteConnection::ScalarString(char* sql, int row=0, int col=0) { rc = sqlite3_finalize(stmt); throw std::runtime_error("column number out of range"); } - char* result = sqlite3_column_text(stmt, col); + char* result = csound->strdup((char*) sqlite3_column_text(stmt, col)); rc = sqlite3_finalize(stmt); return result; } @@ -111,21 +113,11 @@ int SqliteConnection::RowCount(sqlite3_stmt* stmt) { return rowCount; } + void SqliteConnection::ToArray(sqlite3_stmt* stmt, csnd::Csound* csound, ARRAYDAT* array, bool asString) { - int colNum = sqlite3_column_count(stmt); - int rowNum = RowCount(stmt); - int totalResults = colNum * rowNum; - array->sizes = csound->calloc(sizeof(int32_t) * 2); - array->sizes[0] = rowNum; - array->sizes[1] = colNum; - array->dimensions = 2; - CS_VARIABLE *var = array->arrayType->createVariable(csound, NULL); - array->arrayMemberSize = var->memBlockSize; - array->data = csound->calloc(var->memBlockSize * totalResults); - STRINGDAT* strings; - if (asString) { - strings = (STRINGDAT*) array->data; - } + int cols = sqlite3_column_count(stmt); + int rows = RowCount(stmt); + STRINGDAT* strings = arrayInit(csound, array, rows, cols); int colIndex; int rowIndex; @@ -133,11 +125,9 @@ void SqliteConnection::ToArray(sqlite3_stmt* stmt, csnd::Csound* csound, ARRAYDA int rc = sqlite3_step(stmt); while (rc != SQLITE_DONE && rc != SQLITE_OK) { colIndex = 0; - while (colIndex < colNum) { + while (colIndex < cols) { if (asString) { - char* item = sqlite3_column_text(stmt, colIndex); - strings[index].size = strlen(item) + 1; - strings[index].data = csound->strdup(item); + insertArrayStringItem(csound, strings, index, (char*) sqlite3_column_text(stmt, colIndex)); } else { array->data[index] = (MYFLT) sqlite3_column_double(stmt, colIndex); } diff --git a/src/tools.cpp b/src/tools.cpp new file mode 100644 index 0000000..ec8863b --- /dev/null +++ b/src/tools.cpp @@ -0,0 +1,54 @@ +/* + tools.cpp + Copyright (C) 2022 Richard Knight + + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + */ + +#include <plugin.h> + +STRINGDAT* arrayInit(csnd::Csound* csound, ARRAYDAT* array, int rows, int cols) { + int totalResults = rows * cols; + size_t totalAllocated; + + if (array->data == NULL) { + array->sizes = (int32_t*) csound->calloc(sizeof(int32_t) * 2); + array->sizes[0] = rows; + array->sizes[1] = cols; + array->dimensions = 2; + CS_VARIABLE *var = array->arrayType->createVariable(csound->get_csound(), NULL); + array->arrayMemberSize = var->memBlockSize; + totalAllocated = array->arrayMemberSize * totalResults; + array->data = (MYFLT*) csound->calloc(totalAllocated); + } else if ((totalAllocated = array->arrayMemberSize * totalResults) > array->allocated) { + array->data = (MYFLT*) csound->realloc(array->data, totalAllocated); + memset((char*)(array->data)+array->allocated, '\0', totalAllocated - array->allocated); + array->allocated = totalAllocated; + } + + // convenience return to be used if it is a string array + return (STRINGDAT*) array->data; +} + + +void insertArrayStringItem(csnd::Csound* csound, STRINGDAT* strings, int index, char* item) { + strings[index].size = strlen(item) + 1; + if (strings[index].data != NULL) { + csound->free(strings[index].data); + } + strings[index].data = csound->strdup(item); +}
\ No newline at end of file |