-
Notifications
You must be signed in to change notification settings - Fork 320
Expand file tree
/
Copy pathCMakeLists.txt
More file actions
437 lines (382 loc) Β· 15.5 KB
/
CMakeLists.txt
File metadata and controls
437 lines (382 loc) Β· 15.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
cmake_minimum_required(VERSION 3.18...3.27)
# Warn if the user invokes CMake directly
if (NOT SKBUILD)
message(WARNING "\
This CMake file is meant to be executed using 'scikit-build-core'.
Running it directly will almost certainly not produce the desired
result. If you are a user trying to install this package, use the
command below, which will install all necessary build dependencies,
compile the package in an isolated environment, and then install it.
=====================================================================
$ pip install .
=====================================================================
If you are a software developer, and this is your own package, then
it is usually much more efficient to install the build dependencies
in your environment once and use the following command that avoids
a costly creation of a new virtual environment at every compilation:
=====================================================================
$ pip install pybind11 scikit-build-core[pyproject]
$ pip install --no-build-isolation -ve .
=====================================================================
You may optionally add -Ceditable.rebuild=true to auto-rebuild when
the package is imported. Otherwise, you need to rerun the above
after editing C++ files.")
endif()
# Find Python and pybind11 first, as we need the interpreter
set(PYBIND11_FINDPYTHON ON)
find_package(Python COMPONENTS Interpreter Development.Module REQUIRED)
find_package(pybind11 CONFIG REQUIRED)
message(STATUS "DEBUG: Python_FOUND: ${Python_FOUND}")
message(STATUS "DEBUG: Python_Interpreter_FOUND: ${Python_Interpreter_FOUND}")
message(STATUS "DEBUG: Python_Development_FOUND: ${Python_Development_FOUND}")
message(STATUS "DEBUG: Python_Development.Module_FOUND: ${Python_Development.Module_FOUND}")
message(STATUS "DEBUG: Python_LIBRARIES: ${Python_LIBRARIES}")
message(STATUS "DEBUG: Python_LIBRARY_DIRS: ${Python_LIBRARY_DIRS}")
message(STATUS "DEBUG: Python_INCLUDE_DIRS: ${Python_INCLUDE_DIRS}")
message(STATUS "DEBUG: Python_EXECUTABLE: ${Python_EXECUTABLE}")
message(STATUS "DEBUG: Python_VERSION: ${Python_VERSION}")
# TODO(psobot): This shouldn't be necessary, but our CI build fails on Windows without it.
if(WIN32 AND NOT DEFINED Python_LIBRARY)
# Dynamically construct the Python_LIBRARY path using version info from find_package(Python)
if (NOT Python_VERSION)
message(FATAL_ERROR "Python_VERSION not set after find_package(Python). Cannot construct Python library path.")
endif()
# Split the version string into major, minor, and patch parts
string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\.(.+)" _ ${Python_VERSION})
set(Python_VERSION_MAJOR ${CMAKE_MATCH_1})
set(Python_VERSION_MINOR ${CMAKE_MATCH_2})
set(Python_VERSION_PATCH ${CMAKE_MATCH_3})
set(DYNAMIC_PYTHON_LIB_FILENAME "python${Python_VERSION_MAJOR}${Python_VERSION_MINOR}.lib")
set(EXPECTED_PYTHON_VERSION_DIR "C:/hostedtoolcache/windows/Python/${Python_VERSION}/x64/libs")
set(Python_LIBRARY "${EXPECTED_PYTHON_VERSION_DIR}/${DYNAMIC_PYTHON_LIB_FILENAME}")
message(STATUS "DEBUG: On Windows, constructed DYNAMIC_PYTHON_LIB_FILENAME: ${DYNAMIC_PYTHON_LIB_FILENAME}")
message(STATUS "DEBUG: On Windows, constructed Python_LIBRARY path: ${Python_LIBRARY}")
endif()
# Set up ccache if available
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
message(STATUS "Using ccache: ${CCACHE_PROGRAM}")
endif()
# Extract version from pedalboard/version.py
execute_process(
COMMAND ${CMAKE_COMMAND} -E echo "with open('pedalboard/version.py') as f: exec(f.read()); print(MAJOR, MINOR, PATCH, sep='.')"
COMMAND ${Python_EXECUTABLE} -
OUTPUT_VARIABLE PEDALBOARD_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
project(pedalboard
VERSION ${PEDALBOARD_VERSION}
LANGUAGES CXX C
DESCRIPTION "A Python library for adding effects to audio."
)
# Global flags
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# Debug/Release configuration
option(DEBUG "Build with debug symbols" OFF)
if(DEBUG)
add_compile_definitions(DEBUG=1 _DEBUG=1)
add_compile_options(-O0 -g)
else()
if(MSVC)
add_compile_options(/Ox)
else()
add_compile_options(-O3)
endif()
endif()
# Add flags based on compiler/platform
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
add_compile_options(-Wall)
endif()
# Set up includes and library sources
set(ALL_INCLUDES
"vendors/pybind11/include/"
"JUCE/modules/"
"JUCE/modules/juce_audio_processors/format_types/VST3_SDK/"
"JUCE/modules/juce_audio_formats/codecs/"
"vendors/"
"vendors/libgsm/inc/"
"vendors/lame/include/"
"vendors/lame/libmp3lame/"
"vendors/lame/"
)
# Add any paths containing subfolders that need to be included
file(GLOB GSM_INCLUDE_DIRS "vendors/libgsm/inc")
list(APPEND ALL_INCLUDES ${GSM_INCLUDE_DIRS})
# Platform-specific settings
if(APPLE)
# macOS specific flags
add_compile_definitions(MACOS=1 HAVE_VDSP=1)
# MacOS Frameworks
find_library(ACCELERATE_FRAMEWORK Accelerate REQUIRED)
find_library(APPKIT_FRAMEWORK AppKit REQUIRED)
find_library(AUDIOTOOLBOX_FRAMEWORK AudioToolbox REQUIRED)
find_library(COCOA_FRAMEWORK Cocoa REQUIRED)
find_library(COREAUDIO_FRAMEWORK CoreAudio REQUIRED)
find_library(COREAUDIOKIT_FRAMEWORK CoreAudioKit REQUIRED)
find_library(COREMIDI_FRAMEWORK CoreMIDI REQUIRED)
find_library(FOUNDATION_FRAMEWORK Foundation REQUIRED)
find_library(IOKIT_FRAMEWORK IOKit REQUIRED)
find_library(QUARTZ_FRAMEWORK QuartzCore REQUIRED)
find_library(WEBKIT_FRAMEWORK WebKit REQUIRED)
set(MACOS_FRAMEWORKS
${ACCELERATE_FRAMEWORK}
${APPKIT_FRAMEWORK}
${AUDIOTOOLBOX_FRAMEWORK}
${COCOA_FRAMEWORK}
${COREAUDIO_FRAMEWORK}
${COREAUDIOKIT_FRAMEWORK}
${COREMIDI_FRAMEWORK}
${FOUNDATION_FRAMEWORK}
${IOKIT_FRAMEWORK}
${QUARTZ_FRAMEWORK}
${WEBKIT_FRAMEWORK}
)
add_compile_definitions(JUCE_PLUGINHOST_AU=1)
# No threading code needed on macOS, vDSP does this for us
add_compile_definitions(NO_THREADING)
# File extension handling for Objective-C++
list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES ".mm")
elseif(WIN32)
# Windows specific flags
add_compile_definitions(WINDOWS=1 USE_BUILTIN_FFT NO_THREADING)
add_compile_definitions(JUCE_DLL_BUILD=1)
# Windows-specific libraries
list(APPEND PLATFORM_LIBRARIES
kernel32 user32 gdi32 winspool comdlg32 advapi32 shell32
ole32 oleaut32 uuid odbc32 odbccp32
)
elseif(UNIX AND NOT APPLE)
# Linux specific flags
add_compile_definitions(LINUX=1)
# FFTW support for Linux
add_compile_definitions(
HAVE_FFTW3=1
LACK_SINCOS=1
FFTW_DOUBLE_ONLY=1
USE_PTHREADS
)
# Linux Dependencies
find_package(PkgConfig REQUIRED)
pkg_check_modules(FREETYPE REQUIRED freetype2)
find_package(ALSA REQUIRED)
include_directories(${FREETYPE_INCLUDE_DIRS})
list(APPEND PLATFORM_LIBRARIES ${FREETYPE_LIBRARIES} ${ALSA_LIBRARIES})
# Processor-specific optimizations (x86 vs ARM)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm|aarch64")
add_compile_definitions(HAVE_NEON=1)
else()
# Use -mavx by default for portable binaries (AVX is baseline since
# Sandy Bridge, 2011). Set USE_MARCH_NATIVE=1 to optimize for the
# local CPU instead (useful for developer builds, but the resulting
# binaries may crash on other hardware).
if(DEFINED ENV{USE_MARCH_NATIVE})
add_compile_options(-march=native)
else()
add_compile_options(-mavx)
endif()
add_compile_definitions(HAVE_AVX)
endif()
# Additional Linux flags
list(APPEND ALL_INCLUDES "vendors/fftw3/api/" "vendors/fftw3/")
endif()
# JUCE-related flags
list(APPEND JUCE_COMPILE_DEFINITIONS
JUCE_DISPLAY_SPLASH_SCREEN=1
JUCE_USE_DARK_SPLASH_SCREEN=1
JUCE_MODULE_AVAILABLE_juce_audio_basics=1
JUCE_MODULE_AVAILABLE_juce_audio_formats=1
JUCE_MODULE_AVAILABLE_juce_audio_processors=1
JUCE_MODULE_AVAILABLE_juce_core=1
JUCE_MODULE_AVAILABLE_juce_data_structures=1
JUCE_MODULE_AVAILABLE_juce_dsp=1
JUCE_MODULE_AVAILABLE_juce_events=1
JUCE_MODULE_AVAILABLE_juce_graphics=1
JUCE_MODULE_AVAILABLE_juce_gui_basics=1
JUCE_MODULE_AVAILABLE_juce_gui_extra=1
JUCE_MODULE_AVAILABLE_juce_audio_devices=1
JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1
JUCE_STRICT_REFCOUNTEDPOINTER=1
JUCE_STANDALONE_APPLICATION=1
JUCER_LINUX_MAKE_6D53C8B4=1
JUCE_APP_VERSION=1.0.0
JUCE_APP_VERSION_HEX=0x10000
JucePlugin_Build_VST=0
JucePlugin_Build_VST3=0
JucePlugin_Build_AU=0
JucePlugin_Build_AUv3=0
JucePlugin_Build_RTAS=0
JucePlugin_Build_AAX=0
JucePlugin_Build_Standalone=0
JucePlugin_Build_Unity=0
JUCE_DISABLE_JUCE_VERSION_PRINTING=1
JUCE_WEB_BROWSER=0
JUCE_USE_CURL=0
JUCE_USE_MP3AUDIOFORMAT=0
JUCE_USE_FLAC=0
JUCE_MODAL_LOOPS_PERMITTED=1
)
if(DEFINED ENV{CIBW_BUILD} AND "$ENV{CIBW_BUILD}" MATCHES "musllinux")
# For Alpine/musllinux compatibility:
add_compile_definitions(
_NL_IDENTIFICATION_LANGUAGE=0x42
_NL_IDENTIFICATION_TERRITORY=0x43
)
endif()
# Rubber Band library flags
list(APPEND RUBBERBAND_COMPILE_DEFINITIONS
USE_BQRESAMPLER=1
_HAS_STD_BYTE=0
NOMINMAX
ALREADY_CONFIGURED
)
# Helper function to collect source files
function(collect_sources)
# Collect all C++ source files
file(GLOB_RECURSE CPP_SOURCES "pedalboard/*.cpp")
# Handle platform-specific sources
if(APPLE)
file(GLOB_RECURSE OBJC_SOURCES "pedalboard/*.mm")
# Exclude specific files that shouldn't be compiled directly
list(FILTER OBJC_SOURCES EXCLUDE REGEX ".*juce_mac_PatchedWindowing\\.mm$")
foreach(OBJC_SOURCE ${OBJC_SOURCES})
get_filename_component(BASENAME ${OBJC_SOURCE} NAME_WE)
list(FILTER CPP_SOURCES EXCLUDE REGEX ".*/${BASENAME}\\.cpp$")
endforeach()
list(APPEND CPP_SOURCES ${OBJC_SOURCES})
endif()
# We explicitly patch include_juce_gui_basics.{mm,cpp} with juce_patched_gui_basics.cpp,
# so remove the latter from the list of C++ sources
list(FILTER CPP_SOURCES EXCLUDE REGEX ".*juce_patched_gui_basics\\.cpp$")
# Collect RubberBand sources
file(GLOB RUBBERBAND_SOURCES "vendors/rubberband/single/*.cpp")
# Collect general vendor sources
file(GLOB VENDOR_SOURCES "vendors/*.c" "vendors/*.cpp")
# LAME/mpglib sources
file(GLOB LAME_SOURCES "vendors/lame/libmp3lame/*.c" "vendors/lame/libmp3lame/vector/*.c" "vendors/lame/mpglib/*.c")
# libgsm sources (excluding toast files)
file(GLOB GSM_SOURCES "vendors/libgsm/src/*.c")
list(FILTER GSM_SOURCES EXCLUDE REGEX ".*toast.*")
# FFTW sources for Linux
if(UNIX AND NOT APPLE AND NOT DEFINED CIBW_BUILD OR NOT CIBW_BUILD MATCHES "musllinux")
file(GLOB_RECURSE FFTW_SOURCES "vendors/fftw3/*.c")
# Exclude files depending on architecture
if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm|aarch64")
list(FILTER FFTW_SOURCES EXCLUDE REGEX ".*(avx|/sse).*")
else()
list(FILTER FFTW_SOURCES EXCLUDE REGEX ".*neon.*")
endif()
# Exclude unused FFTW components
list(FILTER FFTW_SOURCES EXCLUDE REGEX ".*(altivec|vsx|mpi|threads|tests|tools|/support|common/|libbench|sse2|avx2|avx512|kcvi|avx-128-fma|generic-simd).*")
endif()
# Combine all sources
set(ALL_SOURCES
${CPP_SOURCES}
${RUBBERBAND_SOURCES}
${VENDOR_SOURCES}
${LAME_SOURCES}
${GSM_SOURCES}
${FFTW_SOURCES}
PARENT_SCOPE
)
endfunction()
# Call the function to collect all source files
collect_sources()
# Create the Python module
pybind11_add_module(pedalboard_native ${ALL_SOURCES})
# Add include directories
target_include_directories(pedalboard_native PRIVATE ${ALL_INCLUDES})
if(APPLE)
# Objective-C++ support for macOS, but only when compiling C++, not C:
target_compile_options(pedalboard_native PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-xobjective-c++>)
endif()
# Add JUCE and other compile definitions
target_compile_definitions(pedalboard_native PRIVATE ${JUCE_COMPILE_DEFINITIONS})
target_compile_definitions(pedalboard_native PRIVATE ${RUBBERBAND_COMPILE_DEFINITIONS})
# LAME config
if(WIN32)
target_compile_definitions(pedalboard_native PRIVATE
HAVE_MPGLIB
HAVE_XMMINTRIN_H
)
target_compile_options(pedalboard_native PRIVATE
"/FI${CMAKE_CURRENT_SOURCE_DIR}/vendors/lame_config.h"
)
else()
target_compile_definitions(pedalboard_native PRIVATE
HAVE_MPGLIB
)
target_compile_options(pedalboard_native PRIVATE
"-include${CMAKE_CURRENT_SOURCE_DIR}/vendors/lame_config.h"
)
endif()
# Link libraries
if(APPLE)
target_link_libraries(pedalboard_native PRIVATE ${MACOS_FRAMEWORKS})
elseif(WIN32)
target_link_libraries(pedalboard_native PRIVATE ${PLATFORM_LIBRARIES})
# Link Python libraries
if(Python_LIBRARIES)
# This is the ideal case, FindPython worked as expected.
message(STATUS "DEBUG: Linking against Python_LIBRARIES: ${Python_LIBRARIES}")
target_link_libraries(pedalboard_native PRIVATE ${Python_LIBRARIES})
elseif(DEFINED Python_LIBRARY AND EXISTS "${Python_LIBRARY}")
# Fallback: Python_LIBRARIES is empty, but we have an explicit Python_LIBRARY path.
message(STATUS "DEBUG: Python_LIBRARIES is empty. Linking directly against Python_LIBRARY: ${Python_LIBRARY}")
target_link_libraries(pedalboard_native PRIVATE "${Python_LIBRARY}")
else()
# Critical error: No way to link Python library on Windows.
message(FATAL_ERROR "DEBUG: On Windows, Python_LIBRARIES is empty AND Python_LIBRARY is not set or path does not exist ('${Python_LIBRARY}'). Cannot link Python.")
endif()
elseif(UNIX AND NOT APPLE)
# Add libatomic for atomic operations on Linux
target_link_libraries(pedalboard_native PRIVATE ${PLATFORM_LIBRARIES} atomic)
# Add missing FFTW-specific C flags for Linux
target_compile_options(pedalboard_native PRIVATE
$<$<COMPILE_LANGUAGE:C>:
-DHAVE_UINTPTR_T
-DPACKAGE="FFTW"
-DVERSION="0"
-DPACKAGE_VERSION="00000"
-DFFTW_CC="clang"
"-includestring.h"
"-includestdint.h"
"-include${CMAKE_CURRENT_SOURCE_DIR}/vendors/fftw3/dft/codelet-dft.h"
"-include${CMAKE_CURRENT_SOURCE_DIR}/vendors/fftw3/rdft/codelet-rdft.h"
"-includesys/time.h"
-DHAVE_INTTYPES_H
-DHAVE_STDINT_H
-DHAVE_STDLIB_H
-DHAVE_STRING_H
-DHAVE_TIME_H
-DHAVE_SYS_TIME_H=1
-DHAVE_UNISTD_H
-DHAVE_DECL_DRAND48
-DHAVE_DECL_SRAND48
-DHAVE_DECL_COSL
-DHAVE_DECL_SINL
-DHAVE_DECL_POSIX_MEMALIGN
-DHAVE_DRAND48
-DHAVE_SRAND48
-DHAVE_POSIX_MEMALIGN
-DHAVE_ISNAN
-DHAVE_SNPRINTF
-DHAVE_STRCHR
-DHAVE_SYSCTL
-DHAVE_GETTIMEOFDAY>
)
endif()
# Add LTO if not debugging and not explicitly disabled
if(NOT DEBUG AND NOT DEFINED ENV{DISABLE_LTO})
include(CheckIPOSupported)
check_ipo_supported(RESULT HAVE_IPO)
if(HAVE_IPO)
set_property(TARGET pedalboard_native PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
endif()
endif()
# Install targets
install(TARGETS pedalboard_native DESTINATION .)