diff --git a/.gitignore b/.gitignore index 7f830b1..f08554c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +*~ CMakeCache.txt CMakeFiles/ CMakeScripts/ @@ -18,9 +19,14 @@ cmake_install.cmake *.vcxproj.filters *.vcxproj.user /Makefile +/libportmidi.so +/libportmidi.a +/libportmidi_s.a /libpmjni.so +/packaging/PortMidiConfig.cmake +/packaging/PortMidiConfigVersion.cmake +/packaging/portmidi.pc /pm_common/Makefile -/pm_common/libportmidi-static.a /pm_java/Makefile /pm_test/Makefile /pm_test/fastrcv @@ -36,3 +42,5 @@ cmake_install.cmake /pm_test/sysex /pm_test/testio /pm_test/virttest +/pm_test/fast + diff --git a/CMakeLists.txt b/CMakeLists.txt index 54e074d..e0c7fd2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,41 +1,70 @@ # portmidi -# Roger B. Dannenberg -# 20 Sep 2009 +# Roger B. Dannenberg (and others) +# Sep 2009 - 2021 + +cmake_minimum_required(VERSION 3.12) +# (ALSA::ALSA new in 3.12 and used in pm_common/CMakeLists.txt) + +# Previously, PortMidi versions were simply SVN commit version numbers. +# Versions are now in the form x.y.z +# Changed 1.0 to 2.0 because API is extended with virtual ports +project(portmidi VERSION 2.0.1 + DESCRIPTION "Cross-Platform MIDI IO") +set(SOVERSION 1) + +option(BUILD_SHARED_LIBS "Build shared libraries" ON) -cmake_minimum_required(VERSION 2.8.12) set(CMAKE_OSX_DEPLOYMENT_TARGET 10.9 CACHE STRING "make for this OS version or higher") -if(UNIX) - # allow user to set Release or Debug - set(CMAKE_BUILD_TYPE Release CACHE STRING - "Semicolon-separate list of supported configuration types") - # set default directories but don't override cached values... -# these cause problems for other projects that include this one: -# set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE} -# CACHE STRING "libraries go here") -# set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE} -# CACHE STRING "libraries go here") -# set(CMAKE_RUNTIME_OUTPUT_DIRECTORY -# ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE} -# CACHE STRING "executables go here") -else(UNIX) - # this does not seem to work for xcode: - set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING - "Semicolon-separate list of supported configuration types" OFF) -endif(UNIX) +# PM_ACTUAL_LIB_NAME is in this scope -- see pm_common/CMakeLists.txt + +include(GNUInstallDirs) + +# Build Types +# credit: http://cliutils.gitlab.io/modern-cmake/chapters/features.html +set(DEFAULT_BUILD_TYPE "Release") +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.") + set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE + STRING "Choose the type of build." FORCE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif() + +# where to put libraries? Everything goes here in this directory +# (or Debug or Release, depending on the OS) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -option(BUILD_SHARED_LIBS "Build shared libraries" OFF) option(BUILD_PMDEFAULTS "build the legacy Java application PmDefaults" OFF) option(BUILD_JAVA_NATIVE_INTERFACE "build the Java PortMidi interface library" OFF) +# Defines are used in both portmidi (in pm_common/) and pmjni (in pm_java), +# so define them here to be inherited by both libraries. +# +# PortMidi software architecture supports multiple system API's to lower- +# level MIDI drivers, e.g. PMNULL (no drivers), Jack (but not supported yet), +# and sndio (BSD, not supported yet). Interfaces are selected by defining, +# e.g., PMALSA. (In principle, we should require PMCOREMIDI (for macOS) +# and PMWINMM (for windows), but these are assumed. +# +if(APPLE OR WIN32) +else(APPLE_OR_WIN32) + set(LINUX_DEFINES "PMALSA" CACHE STRING "must define either PMALSA or PMNULL") + add_compile_definitions(${LINUX_DEFINES}) +endif(APPLE OR WIN32) + if(BUILD_JAVA_NATIVE_INTERFACE) message(WARNING "Java API and PmDefaults program updated 2021, but support has " "been discontinued. If you need/use this, let developers know.") + set(PMJNI_IF_EXISTS "pmjni") # used by INSTALL below else(BUILD_JAVA_NATIVE_INTERFACE) + set(PMJNI_IF_EXISTS "") # used by INSTALL below if(BUILD_PMDEFAULTS) message(FATAL_ERROR "Cannot build PM_Defaults program (BUILD_PM_DEFAULTS) without option " @@ -43,55 +72,10 @@ else(BUILD_JAVA_NATIVE_INTERFACE) endif(BUILD_PMDEFAULTS) endif(BUILD_JAVA_NATIVE_INTERFACE) -#set(CMAKE_RELATIVE_PATHS ON CACHE STRING "avoid absolute paths" FORCE) - -# Clear out the built-in C++ compiler and link flags for each of the -# unused configurations. -set(CMAKE_CXX_FLAGS_MINSIZEREL "" CACHE INTERNAL "Unused") -set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "" CACHE INTERNAL "Unused") -set(CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL "" CACHE INTERNAL "Unused") -set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "" CACHE INTERNAL "Unused") -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "" CACHE INTERNAL "Unused") -set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "" CACHE INTERNAL "Unused") -set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "" CACHE INTERNAL "Unused") -set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "" CACHE INTERNAL "Unused") -set(CMAKE_OSX_ARCHITECTURES x86_64 CACHE STRING - "change to support other architectures" FORCE) - -PROJECT(portmidi DESCRIPTION "Cross-Platform MIDI IO") - -set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DPM_CHECK_ERRORS=1 ${LINUX_FLAGS}") -set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${LINUX_FLAGS}") -# set(PORTMIDI_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}" CACHE STRING -# "CMake shows the wrong value for CMAKE_C_FLAGS_DEBUG. Here it is." FORCE) -# set(PORTMIDI_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}" CACHE STRING -# "CMake shows the wrong value for CMAKE_C_FLAGS_RELEASE. Here it is." FORCE) - -if(UNIX) - # Problem: if there was an old Debug build and you change - # CMAKE_BUILD_TYPE to Release, then the OUTPUT_DIRECTORY's will - # still be Debug. Try to fix this by checking if the DIRECTORY's - # look wrong, and if so, force them to the defaults: - if(CMAKE_BUILD_TYPE MATCHES "Debug") - set(BAD_DIR "Release") - else(CMAKE_BUILD_TYPE MATCHES "Debug") - set(BAD_DIR "Debug") - endif(CMAKE_BUILD_TYPE MATCHES "Debug") - # use library as reference -- if you give it a non-BAD_DIR location - # then every other path is left alone - if(CMAKE_LIBRARY_OUTPUT_DIRECTORY MATCHES ${BAD_DIR}) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY - ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE} - CACHE STRING "executables go here" FORCE) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY - ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE} - CACHE STRING "libraries go here" FORCE) - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY - ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE} - CACHE STRING "libraries go here" FORCE) - endif(CMAKE_LIBRARY_OUTPUT_DIRECTORY MATCHES ${BAD_DIR}) -endif(UNIX) +# Something like this might help if you need to build for a specific cpu type: +# set(CMAKE_OSX_ARCHITECTURES x86_64 CACHE STRING +# "change to support other architectures" FORCE) include_directories(pm_common porttime) add_subdirectory(pm_common) @@ -107,7 +91,67 @@ if(BUILD_JAVA_NATIVE_INTERFACE) add_subdirectory(pm_java) endif(BUILD_JAVA_NATIVE_INTERFACE) -# generate pc file for pkg-config +# Install the libraries and headers (Linux and Mac OS X command line) +if(UNIX) + INSTALL(TARGETS portmidi ${PMJNI_IF_EXISTS} + EXPORT PortMidiTargets + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") + INSTALL(FILES portmidi.h pmutil.h ../porttime/porttime.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +endif(UNIX) + +# pkgconfig - generate pc file # See https://cmake.org/cmake/help/latest/command/configure_file.html -configure_file(${CMAKE_PROJECT_NAME}.pc.in ${CMAKE_PROJECT_NAME}.pc @ONLY) -install(FILES ${CMAKE_PROJECT_NAME}.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/packaging/portmidi.pc.in + ${CMAKE_CURRENT_BINARY_DIR}/packaging/portmidi.pc @ONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/packaging/portmidi.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + +# CMake config +set(PORTMIDI_INSTALL_CMAKEDIR "lib/cmake/PortMidi") +install( + EXPORT PortMidiTargets + FILE PortMidiTargets.cmake + NAMESPACE PortMidi:: + DESTINATION "${PORTMIDI_INSTALL_CMAKEDIR}" +) +include(CMakePackageConfigHelpers) +configure_package_config_file(packaging/PortMidiConfig.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/packaging/PortMidiConfig.cmake" + INSTALL_DESTINATION "${PORTMIDI_INSTALL_CMAKEDIR}" +) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/packaging/PortMidiConfigVersion.cmake" + VERSION "${CMAKE_PROJECT_VERSION}" + COMPATIBILITY SameMajorVersion +) +install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/packaging/PortMidiConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/packaging/PortMidiConfigVersion.cmake" + DESTINATION "${PORTMIDI_INSTALL_CMAKEDIR}" +) + + + + + +# Finding out what CMake is doing is really hard, e.g. COMPILE_FLAGS +# does not include COMPILE_OPTIONS or COMPILE_DEFINTIONS. Thus, the +# following report is probably not complete... +MESSAGE(STATUS "PortMidi Library name: " ${PM_ACTUAL_LIB_NAME}) +MESSAGE(STATUS "Build type: " ${CMAKE_BUILD_TYPE}) +MESSAGE(STATUS "Library Type: " ${LIB_TYPE}) +MESSAGE(STATUS "Compiler flags: " ${CMAKE_CXX_COMPILE_FLAGS}) +get_directory_property(prop COMPILE_DEFINITIONS) +MESSAGE(STATUS "Compile definitions: " ${prop}) +get_directory_property(prop COMPILE_OPTIONS) +MESSAGE(STATUS "Compile options: " ${prop}) +MESSAGE(STATUS "Compiler cxx debug flags: " ${CMAKE_CXX_FLAGS_DEBUG}) +MESSAGE(STATUS "Compiler cxx release flags: " ${CMAKE_CXX_FLAGS_RELEASE}) +MESSAGE(STATUS "Compiler cxx min size flags: " ${CMAKE_CXX_FLAGS_MINSIZEREL}) +MESSAGE(STATUS "Compiler cxx flags: " ${CMAKE_CXX_FLAGS}) + diff --git a/README.md b/README.md index c282961..1002c6e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,8 @@ This is the canonical release of PortMidi. -See other repositories within [PortMidi](https://github.com/PortMidi) for related code and bindings (although currently, not much is here). +See other repositories within [PortMidi](https://github.com/PortMidi) +for related code and bindings (although currently, not much is here). ## [Full C API documentation is here.](https://portmidi.github.io/portmidi_docs/) @@ -10,8 +11,13 @@ See other repositories within [PortMidi](https://github.com/PortMidi) for relate Use CMake (or ccmake) to create a Makefile for Linux/BSD or a project file for Xcode or MS Visual Studio. Use make or an IDE to compile. -libportmidi_s.* is a static library (recommended - fewer things can go wrong); -libportmidi.* is a dynamic library. + +**PmDefaults** is a Java-based program for setting default MIDI +devices. It is necessary if you use `Pm_DefaultInputDeviceID()` or +`Pm_DefaultOutputDeviceID()` to avoid implementing your own device +browsing, selection and preferences in your applications. Enable +`BUILD_PMDEFAULTS` and `BUILD_JAVA_NATIVE_INTERFACE` in ccmake, and +see `pm_java/README.txt` for more information. ## What's New? diff --git a/README.txt b/README.txt index 3260823..24cc018 100755 --- a/README.txt +++ b/README.txt @@ -2,19 +2,16 @@ README for PortMidi Roger B. Dannenberg -VERSION: please use "svn info" to get info. - Documentation for PortMidi is found in pm_common/portmidi.h. +Documentation in HTML is available at portmidi.github.io/portmidi_docs/ Additional documentation: + - README.md (overview, how to build, what's new) - Windows: see pm_win/README_WIN.txt and pm_win/debugging_dlls.txt - Linux: see pm_linux/README_LINUX.txt - Mac OSX: see pm_mac/README_MAC.txt - - Common Lisp: see pm_cl/README_CL.txt - - Eclipse: see portmidi_cdt.zip (this was contributed as is; the dlls here - are now -- Sep 09 -- out of date. What is really needed is a script - to generate this release automatically so we can maintain it.) - - C-Sharp: see pm_csharp.zip (also contributed as is) + - Other Languages: look for other repos at github.com/PortMidi, + and search README.md for pointers to other projects. ---------- some notes on the design of PortMidi ---------- diff --git a/packaging/PortMidiConfig.cmake.in b/packaging/PortMidiConfig.cmake.in new file mode 100644 index 0000000..448ae8c --- /dev/null +++ b/packaging/PortMidiConfig.cmake.in @@ -0,0 +1,10 @@ +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) +if(UNIX AND NOT APPLE AND (${LINUX_DEFINES} MATCHES ".*PMALSA.*")) + find_dependency(ALSA) +endif() + +include("${CMAKE_CURRENT_LIST_DIR}/PortMidiTargets.cmake") + +check_required_components(PortMidi) diff --git a/portmidi.pc.in b/packaging/portmidi.pc.in similarity index 100% rename from portmidi.pc.in rename to packaging/portmidi.pc.in diff --git a/pm_common/CMakeLists.txt b/pm_common/CMakeLists.txt index f0ec935..c2f51a7 100644 --- a/pm_common/CMakeLists.txt +++ b/pm_common/CMakeLists.txt @@ -1,4 +1,31 @@ -# pm_common +# pm_common/CMakeLists.txt -- how to build portmidi library + +# Support alternative name for static libraries to avoid confusion. +# (In particular, Xcode has automatically converted portmidi.a to +# portmidi.dylib without warning, so using portmidi-static.a eliminates +# this possibility, but default for all libs is "portmidi"): +set(PM_STATIC_LIB_NAME "portmidi" CACHE STRING + "For static builds, the PortMidi library name, e.g. portmidi-static. + Default is portmidi") +set(PM_ACTUAL_LIB_NAME "portmidi" PARENT_SCOPE) # shared with pm_tests +if(NOT BUILD_SHARED_LIBS) + set(PM_ACTUAL_LIB_NAME ${PM_STATIC_LIB_NAME}) +endif() + +# we need full paths to sources because they are shared with other targets +# (in particular pmjni). Set PMDIR to the top-level portmidi directory: +get_filename_component(PMDIR ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY) +set(PM_LIB_PUBLIC_SRC ${PMDIR}/pm_common/portmidi.c + ${PMDIR}/pm_common/pmutil.c + ${PMDIR}/porttime/porttime.c) +add_library(portmidi ${PM_LIB_PUBLIC_SRC}) +set_target_properties(portmidi PROPERTIES + OUTPUT_NAME "${PM_ACTUAL_LIB_NAME}" + WINDOWS_EXPORT_ALL_SYMBOLS TRUE) +target_include_directories(portmidi PUBLIC + $ + $) + # set the build directory for libportmidi.a to be in portmidi, not in # portmidi/pm_common @@ -7,21 +34,23 @@ if(APPLE OR WIN32) # set the build directory for .dylib libraries set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) - -# Debugging code to figure out what CMake is doing - # the first time CMake configures, save off CMake's built-in flags -# if(NOT DEFAULT_DEBUG_FLAGS) -# set(DEFAULT_DEBUG_FLAGS ${CMAKE_C_FLAGS_DEBUG} CACHE -# STRING "CMake's default debug flags" FORCE) -# set(DEFAULT_RELEASE_FLAGS ${CMAKE_C_FLAGS_RELEASE} CACHE -# STRING "CMake's default release flags" FORCE) -# else(NOT DEFAULT_DEBUG_FLAGS) -# message(STATUS "DEFAULT_DEBUG_FLAGS not nil: " ${DEFAULT_DEBUG_FLAGS}) -# endif(NOT DEFAULT_DEBUG_FLAGS) -else(APPLE OR WIN32) - set(LINUX_FLAGS "-DPMALSA" CACHE STRING "must define either PMALSA or PMNULL") endif(APPLE OR WIN32) +option(PM_CHECK_ERRORS +"Insert a check for error return values at the end of each PortMidi function. +If an error is encountered, a text message is printed using printf(), the user +is asked to type ENTER, and then exit(-1) is called to clean up and terminate +the program. + +You should not use PM_CHECK_ERRORS if printf() does not work (e.g. this is not +a console application under Windows, or there is no visible console on some +other OS), and you should not use PM_CHECK_ERRORS if you intend to recover +from errors rather than abruptly terminate the program." OFF) +if(PM_CHECK_ERRORS) + target_compile_definitions(portmidi PRIVATE PM_CHECK_ERRORS) +endif(PM_CHECK_ERRORS) + + if(APPLE) # set(PM_OSX_VERSION "10.7" CACHE STRING # "selects PM_OSX_SDK and macosx-version-min C flag") @@ -32,7 +61,7 @@ if(APPLE) STRING "needed in conjunction with CMAKE_OSX_SYSROOT" FORCE) # option(OSX_RPATH "control CMake policy for finding macOS dynamic libraries" # ON) # enabled here to match CMake default. Is this correct? -endif(APPLE) +endif() macro(prepend_path RESULT PATH) set(${RESULT}) @@ -42,90 +71,55 @@ macro(prepend_path RESULT PATH) endmacro(prepend_path) # first include the appropriate system-dependent file: -if(UNIX) - if(APPLE) - set(MACSRC pmmacosxcm.c pmmacosxcm.h pmmac.c pmmac.h - readbinaryplist.c readbinaryplist.h finddefault.c) - prepend_path(LIBSRC ${PROJECT_SOURCE_DIR}/pm_mac/ ${MACSRC}) - list(APPEND LIBSRC ${PROJECT_SOURCE_DIR}/porttime/ptmacosx_mach.c) - - include_directories(${CMAKE_OSX_SYSROOT}/Developer/Headers/FlatCarbon) - set(FRAMEWORK_PATH ${CMAKE_OSX_SYSROOT}/System/Library/Frameworks) - set(COREAUDIO_LIB "${FRAMEWORK_PATH}/CoreAudio.framework") - set(COREFOUNDATION_LIB "${FRAMEWORK_PATH}/CoreFoundation.framework") - set(COREMIDI_LIB "${FRAMEWORK_PATH}/CoreMIDI.framework") - set(CORESERVICES_LIB "${FRAMEWORK_PATH}/CoreServices.framework") - set(NEEDED_LIBS ${COREAUDIO_LIB} ${COREFOUNDATION_LIB} - ${COREMIDI_LIB} ${CORESERVICES_LIB}) - - if(BUILD_JAVA_NATIVE_INTERFACE) - set(JAVAVM_LIB "${FRAMEWORK_PATH}/JavaVM.framework") - set(JAVA_INCLUDE_PATHS ${JAVAVM_LIB}/Headers) - endif(BUILD_JAVA_NATIVE_INTERFACE) - message(STATUS "SYSROOT: " ${CMAKE_OSX_SYSROOT}) - else(APPLE) - # LINUX settings... - if(BUILD_JAVA_NATIVE_INTERFACE) - include(FindJNI) - message(STATUS "JAVA_INCLUDE_PATH is " ${JAVA_INCLUDE_PATH}) - message(STATUS "JAVA_INCLUDE_PATH2 is " ${JAVA_INCLUDE_PATH2}) - message(STATUS "JAVA_JVM_LIBRARY is " ${JAVA_JVM_LIBRARY}) - set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2}) - # libjvm.so is found relative to JAVA_INCLUDE_PATH: - set(JAVAVM_LIB ${JAVA_JVM_LIBRARY}/libjvm.so) - endif(BUILD_JAVA_NATIVE_INTERFACE) - - set(LINUXSRC pmlinuxalsa.c pmlinuxalsa.h pmlinux.c pmlinux.h - finddefault.c) - prepend_path(LIBSRC ${PROJECT_SOURCE_DIR}/pm_linux/ ${LINUXSRC}) - list(APPEND LIBSRC ${PROJECT_SOURCE_DIR}/porttime/ptlinux.c) - set(NEEDED_LIBS pthread asound) - endif(APPLE) -else(UNIX) - if(WIN32) +if(UNIX AND APPLE) + find_library(COREAUDIO_LIBRARY CoreAudio REQUIRED) + find_library(COREFOUNDATION_LIBRARY CoreFoundation REQUIRED) + find_library(COREMIDI_LIBRARY CoreMidi REQUIRED) + find_library(CORESERVICES_LIBRARY CoreServices REQUIRED) + set(PM_LIB_PRIVATE_SRC + ${PMDIR}/porttime/ptmacosx_mach.c + ${PMDIR}/pm_mac/pmmac.c + ${PMDIR}/pm_mac/pmmacosxcm.c + ${PMDIR}/pm_mac/finddefault.c + ${PMDIR}/pm_mac/readbinaryplist.c) + target_link_libraries(portmidi PRIVATE pthread ${COREAUDIO_LIBRARY} + ${COREFOUNDATION_LIBRARY} ${COREMIDI_LIBRARY} ${CORESERVICES_LIBRARY}) + # set to CMake default; is this right?: + set_target_properties(portmidi PROPERTIES MACOSX_RPATH ON) +elseif(UNIX) + target_compile_definitions(portmidi PRIVATE ${LINUX_FLAGS}) + set(PM_LIB_PRIVATE_SRC + ${PMDIR}/porttime/ptlinux.c + ${PMDIR}/pm_linux/pmlinux.c + ${PMDIR}/pm_linux/pmlinuxnull.c + ${PMDIR}/pm_linux/finddefault.c) + if(${LINUX_DEFINES} MATCHES ".*PMALSA.*") + # Note that ALSA is not required if PMNULL is defined -- PortMidi will then + # compile without ALSA and report no MIDI devices. Later, PMSNDIO or PMJACK + # might be additional options. + find_package(ALSA REQUIRED) + list(APPEND PM_LIB_PRIVATE_SRC ${PMDIR}/pm_linux/pmlinuxalsa.c) + target_link_libraries(portmidi PRIVATE pthread ALSA::ALSA) + else() + message(WARNING "No PMALSA, so PortMidi will not use ALSA, " + "and will not find or open MIDI devices.") + endif() +elseif(WIN32) + set(PM_LIB_PRIVATE_SRC + ${PMDIR}/porttime/ptwinmm.c + ${PMDIR}/pm_windows/pmwin.c + ${PMDIR}/pm_windows/pmwinmm.c) + target_link_libraries(portmidi PRIVATE winmm) + if(NOT BUILD_SHARED_LIBS) # /MDd is multithread debug DLL, /MTd is multithread debug # /MD is multithread DLL, /MT is multithread. Change to static: include(../pm_win/static.cmake) - - if(BUILD_JAVA_NATIVE_INTERFACE) - include(FindJNI) - - set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2}) - # message(STATUS "JAVA_INCLUDE_PATHS: " ${JAVA_INCLUDE_PATHS}) - endif(BUILD_JAVA_NATIVE_INTERFACE) - - set(WINSRC pmwin.c pmwinmm.c pmwinmm.h) - prepend_path(LIBSRC ${PROJECT_SOURCE_DIR}/pm_win/ ${WINSRC}) - list(APPEND LIBSRC ${PROJECT_SOURCE_DIR}/porttime/ptwinmm.c) - set(NEEDED_LIBS winmm.lib) - endif(WIN32) -endif(UNIX) - -# this completes the list of library sources by adding shared code -prepend_path(PMSRC "${CMAKE_CURRENT_SOURCE_DIR}/" - pmutil.c pmutil.h portmidi.c portmidi.h pminternal.h) -list(APPEND LIBSRC ${PMSRC}) - -set(PM_LIB_NAME "portmidi" CACHE STRING - "The PortMidi library name, e.g. portmidi_static. Default is portmidi") - -# now add the shared files to make the complete list of library sources -add_library(${PM_LIB_NAME} ${LIBSRC}) -set(PM_LIBSRC ${LIBSRC} CACHE INTERNAL - "accumulate and share portmidi library sources here") -set(PM_NEEDED_LIBS ${NEEDED_LIBS} CACHE INTERNAL - "accumulate and share portmidi dependencies here") + endif(BUILD_SHARED_LIBS) +else() + message(FATAL_ERROR "Operating system not supported.") +endif() -# set to CMake default; is this right?: -set_target_properties(${PM_LIB_NAME} PROPERTIES MACOSX_RPATH ON) -target_link_libraries(${PM_LIB_NAME} ${PM_NEEDED_LIBS}) +set(PM_LIB_PUBLIC_SRC ${PM_LIB_PUBLIC_SRC} PARENT_SCOPE) # export to parent +set(PM_LIB_PRIVATE_SRC ${PM_LIB_PRIVATE_SRC} PARENT_SCOPE) # export to parent -# install the libraries (Linux and Mac OS X command line) -if(UNIX) - INSTALL(TARGETS ${PM_LIB_NAME} ${PMJNI_LIBRARY} - LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib - ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) -# .h files installed by pm_dylib/CMakeLists.txt, so don't need them here -# INSTALL(FILES portmidi.h ../porttime/porttime.h -# DESTINATION ${CMAKE_INSTALL_PREFIX}/include) -endif(UNIX) +target_sources(portmidi PRIVATE ${PM_LIB_PRIVATE_SRC}) diff --git a/pm_common/portmidi.c b/pm_common/portmidi.c index 8fb8961..9e73cde 100755 --- a/pm_common/portmidi.c +++ b/pm_common/portmidi.c @@ -61,7 +61,7 @@ static void prompt_and_exit(void) { char line[STRING_MAX]; printf("type ENTER..."); - fgets(line, STRING_MAX, stdin); + char *rslt = fgets(line, STRING_MAX, stdin); /* this will clean up open ports: */ exit(-1); } diff --git a/pm_java/CMakeLists.txt b/pm_java/CMakeLists.txt index 62741b1..fc3d1ce 100644 --- a/pm_java/CMakeLists.txt +++ b/pm_java/CMakeLists.txt @@ -1,119 +1,95 @@ -# pm_java +# pm_java/CMakeLists.txt -- builds pmjni and pmdefaults program find_package(Java) message(STATUS "Java_JAVA_EXECUTABLE is " ${Java_JAVA_EXECUTABLE}) + if(BUILD_PMDEFAULTS) - set(JPORTMIDICLASS JPortMidi.class JPortMidiException.class - JPortMidiApi.class) - set(PMDEFAULTSCLASS PmDefaultsFrame.class PmDefaults.class) - prepend_path(JPORTMIDIPATH jportmidi/ ${JPORTMIDICLASS}) - prepend_path(PMDEFAULTSPATH pmdefaults/ ${PMDEFAULTSCLASS}) - set(PMDEFAULTS_ALL ${JPORTMIDIPATH} ${PMDEFAULTSPATH}) + # Since pmdefaults and pmdefaults.bat are in the source tree and look + # for libpmjni in the same tree, out-of-source build will not create + # a working pmdefaults (without more work): + if(NOT ${CMAKE_SOURCE_DIR} EQUAL ${CMAKE_BINARY_DIR}) + message(WARNING "PmDefaults only works when run in the pm_java/pmdefaults directory after an in-source build. This is an out-of-source build, so [probably] libpmjni will be built out-of-source, pmdefaults.jar will be built in-source, and the pmdefaults[.bat] script remains in-source. Rebuild in-source to use PmDefaults or adjust the file locations and scripts to suit yourself.") + endif() - # SOME DEBUGGING INFORMATION IS COMMENTED OUT HERE... - #message(STATUS "Where does CMAKE put things?..." - #message(STATUS " LIBRARY_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_DIRECTORY}") - #message(STATUS " LIBRARY_OUTPUT_PATH ${LIBRARY_OUTPUT_PATH}") - #message(STATUS " RUNTIME_OUTPUT_DIRECTORY ${RUNTIME_OUTPUT_DIRECTORY}") - #message(STATUS - # " CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") - #message(STATUS - # " CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") - #message(STATUS " CMAKE_CURRENT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}") - #message(STATUS - # " CMAKE_BUILD_FILES_DIRECTORY ${CMAKE_BUILD_FILES_DIRECTORY}") - #message(STATUS " CMAKE_BUILD_DIRECTORY ${CMAKE_BUILD_DIRECTORY}") - #message(STATUS " CMAKE_BINARY_DIR ${CMAKE_BINARY_DIR}") - #message(STATUS " EXECUTABLE_OUTPUT_PATH ${EXECUTABLE_OUTPUT_PATH}") + set(JPORTMIDICLASS JPortMidi.class JPortMidiException.class + JPortMidiApi.class) + set(PMDEFAULTSCLASS PmDefaultsFrame.class PmDefaults.class) + prepend_path(JPORTMIDIPATH jportmidi/ ${JPORTMIDICLASS}) + prepend_path(PMDEFAULTSPATH pmdefaults/ ${PMDEFAULTSCLASS}) + set(PMDEFAULTS_ALL ${JPORTMIDIPATH} ${PMDEFAULTSPATH}) project(pmdefaults NONE) include(UseJava) - if(UNIX) # There seems to be a bug in CMake - Linux complains if NAMESPACE is # missing, but Windows does not make a working VS solution if NAMESPACE # is present, so this "add_jar" call is almost duplicated: here for # Linux/macOS and below for Windows... - add_jar(pmdefaults - SOURCES pmdefaults/PmDefaults.java pmdefaults/PmDefaultsFrame.java + add_jar(pmdefaults + SOURCES pmdefaults/PmDefaults.java pmdefaults/PmDefaultsFrame.java jportmidi/JPortMidi.java jportmidi/JPortMidiApi.java jportmidi/JPortMidiException.java RESOURCES NAMESPACE "." pmdefaults/portmusic_logo.png MANIFEST pmdefaults/manifest.txt OUTPUT_DIR pmdefaults) - if(BUILD_JAVA_NATIVE_INTERFACE) - include(FindJNI) - # message(STATUS "JAVA_JVM_LIB_PATH is " ${JAVA_JVM_LIB_PATH}) - # message(STATUS "JAVA_INCLUDE_PATH is " ${JAVA_INCLUDE_PATH}) - # note: should use JAVA_JVM_LIB_PATH, but it is not set properly - # note: user might need to set JAVA_INCLUDE_PATH manually - # - # this will probably break on BSD and other Unix systems; the fix - # depends on whether FindJNI can find Java or not. If yes, then - # we should try to rely on automatically set JAVA_INCLUDE_PATH and - # JAVA_INCLUDE_PATH2; if no, then we need to make both JAVA_INCLUDE_PATH - # and JAVA_INCLUDE_PATH2 set by user (will need clear documentation - # because JAVA_INCLUDE_PATH2 is pretty obscure) - set(JAVA_INCLUDE_PATH ${JAVA_INCLUDE_PATH-UNKNOWN} - CACHE STRING "where to find Java SDK include directory") - set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH}/linux) - # libjvm.so is found relative to JAVA_INCLUDE_PATH: - set(JAVAVM_LIB ${JAVA_INCLUDE_PATH}/../jre/lib/i386/client/libjvm.so) - endif(BUILD_JAVA_NATIVE_INTERFACE) - if(APPLE) - else(APPLE) - # install the libraries (Linux only) - INSTALL(FILES ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/pmdefaults.jar - DESTINATION /usr/share/java) - INSTALL(PROGRAMS ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/pmdefaults - DESTINATION /usr/local/bin) - endif(APPLE) - else(UNIX) - if(WIN32) - add_jar(pmdefaults - SOURCES pmdefaults/PmDefaults.java pmdefaults/PmDefaultsFrame.java - jportmidi/JPortMidi.java jportmidi/JPortMidiApi.java - jportmidi/JPortMidiException.java - # NAMESPACE did not seem to work on Windows - omitting it may - # cause out-of-source-tree builds to fail: - RESOURCES pmdefaults/portmusic_logo.png - MANIFEST pmdefaults/manifest.txt - OUTPUT_DIR pmdefaults) - if(BUILD_JAVA_NATIVE_INTERFACE) - include(FindJNI) - # note: should use JAVA_JVM_LIB_PATH, but it is not set properly - set(JAVAVM_LIB ${JAVA_INCLUDE_PATH}/../lib/jvm.lib) - - set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2}) - # message(STATUS "JAVA_INCLUDE_PATHS: " ${JAVA_INCLUDE_PATHS}) - # message(STATUS "JAVAVM_LIB: " ${JAVAVM_LIB}) - endif(BUILD_JAVA_NATIVE_INTERFACE) - - set(PM_NEEDED_LIBS winmm.lib) - endif(WIN32) - endif(UNIX) + elseif(WIN32) + add_jar(pmdefaults + SOURCES pmdefaults/PmDefaults.java pmdefaults/PmDefaultsFrame.java + jportmidi/JPortMidi.java jportmidi/JPortMidiApi.java + jportmidi/JPortMidiException.java + # NAMESPACE did not seem to work on Windows - omitting it may + # cause out-of-source-tree builds to fail: + RESOURCES pmdefaults/portmusic_logo.png + MANIFEST pmdefaults/manifest.txt + OUTPUT_DIR pmdefaults) + set(PM_NEEDED_LIBS winmm.lib) + set(JAVAVM_LIB ${JAVA_INCLUDE_PATH}/../jre/lib/i386/client/libjvm.so) + endif() + add_dependencies(pmdefaults pmjni) endif(BUILD_PMDEFAULTS) -# define the jni library -include_directories(${JAVA_INCLUDE_PATHS}) +# Build pmjni +# this CMakeLists.txt is only loaded if BUILD_JAVA_NATIVE_INTERFACE +# This jni library includes portmidi sources to give just +# one library for JPortMidi users to manage rather than two. +if(UNIX) + include(FindJNI) + # message(STATUS "JAVA_JVM_LIB_PATH is " ${JAVA_JVM_LIB_PATH}) + # message(STATUS "JAVA_INCLUDE_PATH is " ${JAVA_INCLUDE_PATH}) + # note: should use JAVA_JVM_LIB_PATH, but it is not set properly + # note: user might need to set JAVA_INCLUDE_PATH manually + # + # this will probably break on BSD and other Unix systems; the fix + # depends on whether FindJNI can find Java or not. If yes, then + # we should try to rely on automatically set JAVA_INCLUDE_PATH and + # JAVA_INCLUDE_PATH2; if no, then we need to make both JAVA_INCLUDE_PATH + # and JAVA_INCLUDE_PATH2 set by user (will need clear documentation + # because JAVA_INCLUDE_PATH2 is pretty obscure) + set(JAVA_INCLUDE_PATH ${JAVA_INCLUDE_PATH-UNKNOWN} + CACHE STRING "where to find Java SDK include directory") + # libjvm.so is found relative to JAVA_INCLUDE_PATH: + set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH}/linux) +elseif(WIN32) + include(FindJNI) + # note: should use JAVA_JVM_LIB_PATH, but it is not set properly + set(JAVAVM_LIB ${JAVA_INCLUDE_PATH}/../lib/jvm.lib) -set(JNISRC ${PROJECT_SOURCE_DIR}/pmjni/pmjni.c) + set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2}) + # message(STATUS "JAVA_INCLUDE_PATHS: " ${JAVA_INCLUDE_PATHS}) + # message(STATUS "JAVAVM_LIB: " ${JAVAVM_LIB}) +endif() -# note: PM_LIBSRC is all source for PortMidi, which becomes part of pmjni. -# This means there is no dependency on a separate PortMidi library, and -# pmjni can access internal PortMidi implementation variables and not -# just the "public" API. -message(STATUS "PM_LIBSRC is ${PM_LIBSRC}") -add_library(pmjni SHARED ${JNISRC} ${PM_LIBSRC}) +add_library(pmjni SHARED pmjni/pmjni.c) +target_sources(pmjni PRIVATE ${PM_LIB_PUBLIC_SRC} ${PM_LIB_PRIVATE_SRC}) +message(STATUS "Java paths ${JAVA_INCLUDE_PATHS}") +# message(STATUS "Java pmjni src: pmjni/pmjni.c ${PM_LIB_SHARED_SRC} " +# "${PM_LIB_PRIVATE_SRC}") +target_include_directories(pmjni PUBLIC ${JAVA_INCLUDE_PATHS}) target_link_libraries(pmjni ${PM_NEEDED_LIBS}) - - -set_target_properties(pmjni PROPERTIES +set_target_properties(pmjni PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" EXECUTABLE_EXTENSION "jnilib" - MACOSX_RPATH ON) -set(PMJNI_LIBRARY pmjni) + MACOSX_RPATH ON) -add_dependencies(pmdefaults pmjni) diff --git a/pm_linux/pmlinux.c b/pm_linux/pmlinux.c index 9eda65d..c615531 100755 --- a/pm_linux/pmlinux.c +++ b/pm_linux/pmlinux.c @@ -60,6 +60,9 @@ void pm_term(void) #ifdef PMALSA pm_linuxalsa_term(); #endif + #ifdef PMNULL + pm_linuxnull_term(); + #endif } PmDeviceID Pm_GetDefaultInputDeviceID() { diff --git a/pm_linux/pmlinuxalsa.c b/pm_linux/pmlinuxalsa.c index fc99a2a..2a8efc1 100755 --- a/pm_linux/pmlinuxalsa.c +++ b/pm_linux/pmlinuxalsa.c @@ -7,6 +7,11 @@ * Jason Cohen, Rico Colon, Matt Filippone (Alsa 0.5.x implementation) */ +/* omit this code if PMALSA is not defined -- this mechanism allows + * selection of different MIDI interfaces (at compile time). + */ +#ifdef PMALSA + #include "stdlib.h" #include "portmidi.h" #include "pmutil.h" @@ -826,3 +831,5 @@ void pm_linuxalsa_term(void) pm_descriptor_max = 0; } } + +#endif diff --git a/pm_linux/pmlinuxnull.c b/pm_linux/pmlinuxnull.c new file mode 100644 index 0000000..257f3d6 --- /dev/null +++ b/pm_linux/pmlinuxnull.c @@ -0,0 +1,31 @@ +/* + * pmlinuxnull.c -- system specific definitions + * + * written by: + * Roger Dannenberg + * + * If there is no ALSA, you can define PMNULL and build PortMidi. It will + * not report any devices, so you will not be able to open any, but if + * you wanted to disable MIDI from some application, this could be used. + * Mainly, this code shows the possibility of supporting multiple + * interfaces, e.g., ALSA and Sndio on BSD, or ALSA and Jack on Linux. + * But as of Dec, 2021, the only supported MIDI API for Linux is ALSA. + */ + +#ifdef PMNULL + +#include "portmidi.h" +#include "pmlinuxnull.h" + + +PmError pm_linuxnull_init(void) +{ + return pmNoError; +} + + +void pm_linuxnull_term(void) +{ +} + +#endif diff --git a/pm_linux/pmlinuxnull.h b/pm_linux/pmlinuxnull.h new file mode 100644 index 0000000..9835825 --- /dev/null +++ b/pm_linux/pmlinuxnull.h @@ -0,0 +1,6 @@ +/* pmlinuxnull.h -- system-specific definitions */ + +PmError pm_linuxnull_init(void); +void pm_linuxnull_term(void); + + diff --git a/pm_test/CMakeLists.txt b/pm_test/CMakeLists.txt index adde9cf..ad2d837 100644 --- a/pm_test/CMakeLists.txt +++ b/pm_test/CMakeLists.txt @@ -7,30 +7,33 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) endif(APPLE) if(WIN32) -include(../pm_win/static.cmake) + if(NOT BUILD_SHARED_LIBS) + # /MDd is multithread debug DLL, /MTd is multithread debug + # /MD is multithread DLL, /MT is multithread. Change to static: + include(../pm_win/static.cmake) + endif(BUILD_SHARED_LIBS) endif(WIN32) -macro(make_a_test name) +macro(add_test name) add_executable(${name} ${name}.c) - target_link_libraries(${name} ${PM_LIB_NAME} ${PM_NEEDED_LIBS}) - add_dependencies(${name} ${PM_LIB_NAME}) -endmacro(make_a_test) + target_link_libraries(${name} PRIVATE portmidi) +endmacro(add_test) -make_a_test(testio) -make_a_test(midithread) -make_a_test(midithru) -make_a_test(sysex) -make_a_test(latency) -make_a_test(mm) -make_a_test(midiclock) -make_a_test(qtest) -make_a_test(fast) -make_a_test(fastrcv) +add_test(testio) +add_test(midithread) +add_test(midithru) +add_test(sysex) +add_test(latency) +add_test(mm) +add_test(midiclock) +add_test(qtest) +add_test(fast) +add_test(fastrcv) if(WIN32) # windows does not implement Pm_CreateVirtualInput or Pm_CreateVirtualOutput else(WIN32) -make_a_test(recvvirtual) -make_a_test(sendvirtual) -make_a_test(multivirtual) -make_a_test(virttest) +add_test(recvvirtual) +add_test(sendvirtual) +add_test(multivirtual) +add_test(virttest) endif(WIN32) diff --git a/pm_win/static.cmake b/pm_win/static.cmake index 583b713..7fdad18 100644 --- a/pm_win/static.cmake +++ b/pm_win/static.cmake @@ -1,4 +1,12 @@ # static.cmake -- change flags to link with static runtime libraries +# +# Even when BUILD_SHARED_LIBS is OFF, CMake specifies linking wtih +# multithread DLL, so you give inconsistent linking instructions +# resulting in warning messages from MS Visual Studio. If you want +# a static binary, I've found this approach works to eliminate +# warnings and make everything static: +# +# Changes /MD (multithread DLL) to /MT (multithread static) if(MSVC) foreach(flag_var