Skip to content

Commit

Permalink
Major rewrite of CMake build implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
rbdannenberg committed Dec 24, 2021
1 parent d05eb81 commit c27a5bc
Show file tree
Hide file tree
Showing 15 changed files with 385 additions and 292 deletions.
10 changes: 9 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
*~
CMakeCache.txt
CMakeFiles/
CMakeScripts/
Expand All @@ -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
Expand All @@ -36,3 +42,5 @@ cmake_install.cmake
/pm_test/sysex
/pm_test/testio
/pm_test/virttest
/pm_test/fast

This comment has been minimized.

Copy link
@Be-ing

Be-ing Dec 24, 2021

Contributor

None of this belongs in .gitignore. Just add build*/ to .gitignore and call your CMake build directory build. That way there is no need to list every build artifact individually.

This comment has been minimized.

Copy link
@rbdannenberg

rbdannenberg Dec 27, 2021

Author Contributor

But if you do an in-source build, there seems to be no other way to screen out build artifacts. I don't think anything in .gitignore should ever be added to the repo.

This comment has been minimized.

Copy link
@Be-ing

Be-ing Dec 27, 2021

Contributor

CMake is not intended to output to the same directory as the source code. It is conventional to output to a subdirectory and add that to .gitignore (or you can output to a separate directory outside of the repository entirely).

This comment has been minimized.

Copy link
@rbdannenberg

rbdannenberg Dec 27, 2021

Author Contributor

I think cmake should probably enforce out-of-source builds and there should be a standard place for builds, but until that happens, running cmake "out of the box" produces an in-source build, and I would like things to just work either way.


190 changes: 117 additions & 73 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,97 +1,81 @@
# 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})

This comment has been minimized.

Copy link
@Be-ing

Be-ing Dec 24, 2021

Contributor

Setting compile definitions globally is bad practice. It is better to use target_compile_definitions instead.

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 "
"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)
Expand All @@ -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)

This comment has been minimized.

Copy link
@Be-ing

Be-ing Dec 24, 2021

Contributor

This breaks installation on Windows.

This comment has been minimized.

Copy link
@rbdannenberg

rbdannenberg Dec 27, 2021

Author Contributor

I thought Windows installers were completely outside of the world of command lines an CMake. I'm taking out the if(UNIX) ... endif(UNIX) conditional, but I don't know what to expect or how to test the behavior on Windows.

This comment has been minimized.

Copy link
@Be-ing

Be-ing Dec 27, 2021

Contributor

I'm not talking about packaging for Windows applications (cpack can do that too by the way), just installing the build artifacts. If you don't want to do that, then simply don't run the installation step. There's no need to prevent users from doing that.

This comment has been minimized.

Copy link
@rbdannenberg

rbdannenberg Dec 27, 2021

Author Contributor

Ok, ok, relax. I'm not trying to stop anyone from doing anything; I added the install code to enable users (and thanks for the guidance); I just didn't know it worked for Windows.

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

This comment has been minimized.

Copy link
@Be-ing

Be-ing Dec 24, 2021

Contributor

wrong paths

CMake Error at build/cmake_install.cmake:65 (file):
  file INSTALL cannot find "/home/be/sw/portmidi/portmidi.h": No such file or
  directory

This comment has been minimized.

Copy link
@rbdannenberg

rbdannenberg Dec 27, 2021

Author Contributor

Thanks.

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

12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@

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

## Compiling and Using PortMidi

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?

Expand Down
11 changes: 4 additions & 7 deletions README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 ----------

Expand Down
10 changes: 10 additions & 0 deletions packaging/PortMidiConfig.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@PACKAGE_INIT@

include(CMakeFindDependencyMacro)
if(UNIX AND NOT APPLE AND (${LINUX_DEFINES} MATCHES ".*PMALSA.*"))

This comment has been minimized.

Copy link
@Be-ing

Be-ing Dec 24, 2021

Contributor

${LINUX_DEFINES} is not defined in the context of this script. You can put it into this script when it is generated by using @LINUX_DEFINES@ instead, which will be substituted for the value of the variable when the file is generated from this template. For example: https://github.com/PortAudio/portaudio/blob/master/cmake/PortAudioConfig.cmake.in

This comment has been minimized.

Copy link
@rbdannenberg

rbdannenberg Dec 27, 2021

Author Contributor

Thanks - correction will be pushed soon.

find_dependency(ALSA)
endif()

include("${CMAKE_CURRENT_LIST_DIR}/PortMidiTargets.cmake")

check_required_components(PortMidi)
File renamed without changes.
Loading

0 comments on commit c27a5bc

Please sign in to comment.