1# 2# A collection of functions and macros 3# 4 5# Defines several useful directory paths for the active context. 6macro( def_vars ) 7 set( _SRCDIR "${CMAKE_CURRENT_SOURCE_DIR}" ) 8 set( _INTDIR "${CMAKE_CURRENT_BINARY_DIR}" ) 9 set( _PRVDIR "${CMAKE_CURRENT_BINARY_DIR}/private" ) 10 set( _PUBDIR "${CMAKE_CURRENT_BINARY_DIR}/public" ) 11endmacro() 12 13# Helper to organize sources into folders for the IDEs 14macro( organize_source root prefix sources ) 15 set( cleaned ) 16 foreach( source ${sources} ) 17 # Remove generator expressions 18 string( REGEX REPLACE ".*>:(.*)>*" "\\1" source "${source}" ) 19 string( REPLACE ">" "" source "${source}" ) 20 21 # Remove keywords 22 string( REGEX REPLACE "^[A-Z]+$" "" source "${source}" ) 23 24 # Add to cleaned 25 list( APPEND cleaned "${source}" ) 26 endforeach() 27 28 # Define the source groups 29 if( "${prefix}" STREQUAL "" ) 30 source_group( TREE "${root}" FILES ${cleaned} ) 31 else() 32 source_group( TREE "${root}" PREFIX ${prefix} FILES ${cleaned} ) 33 endif() 34endmacro() 35 36# Given a directory, recurse to all defined subdirectories and assign 37# the given folder name to all of the targets found. 38function( set_dir_folder dir folder) 39 get_property( subdirs DIRECTORY "${dir}" PROPERTY SUBDIRECTORIES ) 40 foreach( sub ${subdirs} ) 41 set_dir_folder( "${sub}" "${folder}" ) 42 endforeach() 43 44 get_property( targets DIRECTORY "${dir}" PROPERTY BUILDSYSTEM_TARGETS ) 45 foreach( target ${targets} ) 46 get_target_property( type "${target}" TYPE ) 47 if( NOT "${type}" STREQUAL "INTERFACE_LIBRARY" ) 48 set_target_properties( ${target} PROPERTIES FOLDER ${folder} ) 49 endif() 50 endforeach() 51endfunction() 52 53# Helper to retrieve the settings returned from pkg_check_modules() 54function( get_package_interface package target ) 55 set( package_includes 56 ${${package}_INCLUDE_DIRS} 57 ) 58 59 set( package_linkdirs 60 ${${package}_LIBDIR} 61 ) 62 63 # We resolve the full path of each library to ensure the 64 # correct one is referenced while linking 65 set( package_libraries ) 66 foreach( lib ${${package}_LIBRARIES} ) 67 find_library( LIB_${lib} ${lib} HINTS ${package_linkdirs} ) 68 list( APPEND package_libraries ${LIB_${lib}} ) 69 endforeach() 70 71 # And add it to our target 72 target_include_directories( ${target} INTERFACE ${package_includes} ) 73 target_link_libraries( ${target} INTERFACE ${package_libraries} ) 74 75 message(STATUS "Interface ${target}:\n\tinclude: ${includes}\n\tLibraries: ${LIBRARIES}") 76endfunction() 77 78# Set the cache and context value 79macro( set_cache_value var value ) 80 set( ${var} "${value}" ) 81 set_property( CACHE ${var} PROPERTY VALUE "${value}" ) 82endmacro() 83 84# Set a CMake variable to the value of the corresponding environment variable 85# if the CMake variable is not already defined. Any addition arguments after 86# the variable name are passed through to set(). 87macro( set_from_env var ) 88 if( NOT DEFINED ${var} AND NOT "$ENV{${var}}" STREQUAL "" ) 89 set( ${var} "$ENV{${var}}" ${ARGN} ) # pass additional args (e.g. CACHE) 90 endif() 91endmacro() 92 93# Set the given property and its config specific brethren to the same value 94function( set_target_property_all target property value ) 95 set_target_properties( "${target}" PROPERTIES "${property}" "${value}" ) 96 foreach( type ${CMAKE_CONFIGURATION_TYPES} ) 97 string( TOUPPER "${property}_${type}" prop ) 98 set_target_properties( "${target}" PROPERTIES "${prop}" "${value}" ) 99 endforeach() 100endfunction() 101 102# Taken from wxWidgets and modified for Audacity 103# 104# cmd_option(<name> <desc> [default] [STRINGS strings]) 105# The default is ON if third parameter isn't specified 106function( cmd_option name desc ) 107 cmake_parse_arguments( OPTION "" "" "STRINGS" ${ARGN} ) 108 109 if( ARGC EQUAL 2 ) 110 if( OPTION_STRINGS ) 111 list( GET OPTION_STRINGS 1 default ) 112 else() 113 set( default ON ) 114 endif() 115 else() 116 set( default ${OPTION_UNPARSED_ARGUMENTS} ) 117 endif() 118 119 if( OPTION_STRINGS ) 120 set( cache_type STRING ) 121 else() 122 set( cache_type BOOL ) 123 endif() 124 125 set( ${name} "${default}" CACHE ${cache_type} "${desc}" ) 126 if( OPTION_STRINGS ) 127 set_property( CACHE ${name} PROPERTY STRINGS ${OPTION_STRINGS} ) 128 129 # Check valid value 130 set( value_is_valid FALSE ) 131 set( avail_values ) 132 foreach( opt ${OPTION_STRINGS} ) 133 if( ${name} STREQUAL opt ) 134 set( value_is_valid TRUE ) 135 break() 136 endif() 137 string( APPEND avail_values " ${opt}" ) 138 endforeach() 139 if( NOT value_is_valid ) 140 message( FATAL_ERROR "Invalid value \"${${name}}\" for option ${name}. Valid values are: ${avail_values}" ) 141 endif() 142 endif() 143 144 set( ${name} "${${name}}" PARENT_SCOPE ) 145endfunction() 146 147# Downloads NuGet packages 148# 149# Why this is needed... 150# 151# To get NuGet to work, you have to add the VS_PACKAGE_REFERENCES 152# property to a target. This target must NOT be a UTILITY target, 153# which is what we use to compile the message catalogs and assemble 154# the manual. We could add that property to the Audacity target and 155# CMake would add the required nodes to the VS project. And when the 156# Audacity target is built, the NuGet packages would get automatically 157# downloaded. This also means that the locale and manual targets 158# must be dependent on the Audacity target so the packages would get 159# downloaded before they execute. This would be handled by the CMake 160# provided ALL_BUILD target which is, by default, set as the startup 161# project in Visual Studio. Sweet right? Well, not quite... 162# 163# We want the Audacity target to be the startup project to provide 164# easier debugging. But, if we do that, the ALL_BUILD target is no 165# longer "in control" and any dependents of the Audacity target would 166# not get built. So, targets like "nyquist" and "plug-ins" would have 167# to be manually built. This is not what we want since Nyquist would 168# not be available during Audacity debugging because the Nyquist runtime 169# would not be copied into the destination folder alonside the Audacity 170# executable. 171# 172# To remedy this conundrum, we simply download the NuGet packages 173# ourselves and make the Audacity target dependent on the targets 174# mentioned above. This ensures that the dest folder is populated 175# and laid out like Audacity expects. 176# 177function( nuget_package dir name version ) 178 # Generate the full package directory name 179 set( pkgdir "${CMAKE_BINARY_DIR}/packages/${name}/${version}" ) 180 181 # Don't download it again if the package directory already exists 182 if( NOT EXISTS "${pkgdir}" ) 183 set( pkgurl "https://www.nuget.org/api/v2/package/${name}/${version}" ) 184 185 # Create the package directory 186 file( MAKE_DIRECTORY "${pkgdir}" ) 187 188 # And download the package into the package directory 189 file( DOWNLOAD "${pkgurl}" "${pkgdir}/package.zip" ) 190 191 # Extract the contents of the package into the package directory 192 execute_process( 193 COMMAND 194 ${CMAKE_COMMAND} -E tar x "${pkgdir}/package.zip" 195 WORKING_DIRECTORY 196 ${pkgdir} 197 ) 198 endif() 199 200 # Return the package directory name to the caller 201 set( ${dir} "${pkgdir}" PARENT_SCOPE ) 202endfunction() 203 204# Determines if the linker supports the "-platform_version" argument 205# on macOS. 206macro( check_for_platform_version ) 207 if( NOT DEFINED LINKER_SUPPORTS_PLATFORM_VERSION ) 208 execute_process( 209 COMMAND 210 ld -platform_version macos 1.1 1.1 211 ERROR_VARIABLE 212 error 213 ) 214 215 if( error MATCHES ".*unknown option.*" ) 216 set( PLATFORM_VERSION_SUPPORTED no CACHE INTERNAL "" ) 217 else() 218 set( PLATFORM_VERSION_SUPPORTED yes CACHE INTERNAL "" ) 219 endif() 220 endif() 221endmacro() 222 223# To be used to compile all C++ in the application and modules 224function( audacity_append_common_compiler_options var use_pch ) 225 if( NOT use_pch ) 226 list( APPEND ${var} 227 PRIVATE 228 # include the correct config file; give absolute path to it, so 229 # that this works whether in src, modules, libraries 230 $<$<PLATFORM_ID:Windows>:/FI${CMAKE_BINARY_DIR}/src/private/configwin.h> 231 $<$<PLATFORM_ID:Darwin>:-include ${CMAKE_BINARY_DIR}/src/private/configmac.h> 232 $<$<NOT:$<PLATFORM_ID:Windows,Darwin>>:-include ${CMAKE_BINARY_DIR}/src/private/configunix.h> 233 ) 234 endif() 235 list( APPEND ${var} 236 -DAUDACITY_VERSION=${AUDACITY_VERSION} 237 -DAUDACITY_RELEASE=${AUDACITY_RELEASE} 238 -DAUDACITY_REVISION=${AUDACITY_REVISION} 239 -DAUDACITY_MODLEVEL=${AUDACITY_MODLEVEL} 240 241 # Version string for visual display 242 -DAUDACITY_VERSION_STRING=L"${AUDACITY_VERSION}.${AUDACITY_RELEASE}.${AUDACITY_REVISION}${AUDACITY_SUFFIX}" 243 244 # This value is used in the resource compiler for Windows 245 -DAUDACITY_FILE_VERSION=L"${AUDACITY_VERSION},${AUDACITY_RELEASE},${AUDACITY_REVISION},${AUDACITY_MODLEVEL}" 246 247 # This renames a good use of this C++ keyword that we don't need 248 # to review when hunting for leaks because of naked new and delete. 249 -DPROHIBITED==delete 250 251 # Reviewed, certified, non-leaky uses of NEW that immediately entrust 252 # their results to RAII objects. 253 # You may use it in NEW code when constructing a wxWindow subclass 254 # with non-NULL parent window. 255 # You may use it in NEW code when the NEW expression is the 256 # constructor argument for a standard smart 257 # pointer like std::unique_ptr or std::shared_ptr. 258 -Dsafenew=new 259 260 $<$<CXX_COMPILER_ID:MSVC>:/permissive-> 261 $<$<CXX_COMPILER_ID:AppleClang,Clang>:-Wno-underaligned-exception-object> 262 $<$<CXX_COMPILER_ID:AppleClang,Clang>:-Werror=return-type> 263 $<$<CXX_COMPILER_ID:AppleClang,Clang>:-Werror=dangling-else> 264 $<$<CXX_COMPILER_ID:AppleClang,Clang>:-Werror=return-stack-address> 265 # Yes, CMake will change -D to /D as needed for Windows: 266 -DWXINTL_NO_GETTEXT_MACRO 267 $<$<CXX_COMPILER_ID:MSVC>:-D_USE_MATH_DEFINES> 268 $<$<CXX_COMPILER_ID:MSVC>:-DNOMINMAX> 269 270 # Define/undefine _DEBUG 271 # Yes, -U to /U too as needed for Windows: 272 $<IF:$<CONFIG:Debug>,-D_DEBUG=1,-U_DEBUG> 273 274 $<$<PLATFORM_ID:Darwin>:-DUSE_AQUA_THEME> 275 ) 276 # Definitions controlled by the AUDACITY_BUILD_LEVEL switch 277 if( AUDACITY_BUILD_LEVEL EQUAL 0 ) 278 list( APPEND ${var} -DIS_ALPHA -DUSE_ALPHA_MANUAL ) 279 elseif( AUDACITY_BUILD_LEVEL EQUAL 1 ) 280 list( APPEND ${var} -DIS_BETA -DUSE_ALPHA_MANUAL ) 281 else() 282 list( APPEND ${var} -DIS_RELEASE ) 283 endif() 284 285 set( ${var} "${${var}}" PARENT_SCOPE ) 286endfunction() 287 288function( import_export_symbol var module_name ) 289 # compute, e.g. "TRACK_UI_API" from module name "mod-track-ui" 290 string( REGEX REPLACE "^mod-" "" symbol "${module_name}" ) 291 string( REGEX REPLACE "^lib-" "" symbol "${symbol}" ) 292 string( TOUPPER "${symbol}" symbol ) 293 string( REPLACE "-" "_" symbol "${symbol}" ) 294 string( APPEND symbol "_API" ) 295 set( "${var}" "${symbol}" PARENT_SCOPE ) 296endfunction() 297 298function( import_symbol_define var module_name ) 299 import_export_symbol( symbol "${module_name}" ) 300 if( CMAKE_SYSTEM_NAME MATCHES "Windows" ) 301 set( value "_declspec(dllimport)" ) 302 elseif( HAVE_VISIBILITY ) 303 set( value "__attribute__((visibility(\"default\")))" ) 304 else() 305 set( value "" ) 306 endif() 307 set( "${var}" "${symbol}=${value}" PARENT_SCOPE ) 308endfunction() 309 310function( export_symbol_define var module_name ) 311 import_export_symbol( symbol "${module_name}" ) 312 if( CMAKE_SYSTEM_NAME MATCHES "Windows" ) 313 set( value "_declspec(dllexport)" ) 314 elseif( HAVE_VISIBILITY ) 315 set( value "__attribute__((visibility(\"default\")))" ) 316 else() 317 set( value "" ) 318 endif() 319 set( "${var}" "${symbol}=${value}" PARENT_SCOPE ) 320endfunction() 321 322# shorten a target name for purposes of generating a dependency graph picture 323function( canonicalize_node_name var node ) 324 # strip generator expressions 325 string( REGEX REPLACE ".*>.*:(.*)>" "\\1" node "${node}" ) 326 # omit the "-interface" for alias targets to modules 327 string( REGEX REPLACE "-interface\$" "" node "${node}" ) 328 # shorten names of standard libraries or Apple frameworks 329 string( REGEX REPLACE "^-(l|framework )" "" node "${node}" ) 330 # shorten paths 331 get_filename_component( node "${node}" NAME_WE ) 332 set( "${var}" "${node}" PARENT_SCOPE ) 333endfunction() 334 335function( audacity_module_fn NAME SOURCES IMPORT_TARGETS 336 ADDITIONAL_DEFINES ADDITIONAL_LIBRARIES LIBTYPE ) 337 338 set( TARGET ${NAME} ) 339 set( TARGET_ROOT ${CMAKE_CURRENT_SOURCE_DIR} ) 340 341 message( STATUS "========== Configuring ${TARGET} ==========" ) 342 343 def_vars() 344 345 if (LIBTYPE STREQUAL "MODULE" AND CMAKE_SYSTEM_NAME MATCHES "Windows") 346 set( REAL_LIBTYPE SHARED ) 347 else() 348 set( REAL_LIBTYPE "${LIBTYPE}" ) 349 endif() 350 add_library( ${TARGET} ${REAL_LIBTYPE} ) 351 352 # Manual propagation seems to be necessary from 353 # interface libraries -- just doing target_link_libraries naming them 354 # doesn't work as promised 355 356 # compute INCLUDES 357 set( INCLUDES ) 358 list( APPEND INCLUDES PUBLIC ${TARGET_ROOT} ) 359 360 # compute DEFINES 361 set( DEFINES ) 362 list( APPEND DEFINES ${ADDITIONAL_DEFINES} ) 363 364 # send the file to the proper place in the build tree, by setting the 365 # appropriate property for the platform 366 if (CMAKE_SYSTEM_NAME MATCHES "Windows") 367 set( DIRECTORY_PROPERTY RUNTIME_OUTPUT_DIRECTORY ) 368 else () 369 set( DIRECTORY_PROPERTY LIBRARY_OUTPUT_DIRECTORY ) 370 endif () 371 372 if (LIBTYPE STREQUAL "MODULE") 373 set( ATTRIBUTES "shape=box" ) 374 set_target_property_all( ${TARGET} ${DIRECTORY_PROPERTY} "${_MODDIR}" ) 375 set_target_properties( ${TARGET} 376 PROPERTIES 377 PREFIX "" 378 FOLDER "modules" # for IDE organization 379 ) 380 if( CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin" ) 381 add_custom_command( 382 TARGET ${TARGET} 383 COMMAND ${CMAKE_COMMAND} 384 -D SRC="${_MODDIR}/${TARGET}.so" 385 -D WXWIN="${_SHARED_PROXY_BASE_PATH}/$<CONFIG>" 386 -P ${AUDACITY_MODULE_PATH}/CopyLibs.cmake 387 POST_BUILD ) 388 endif() 389 else() 390 set( ATTRIBUTES "shape=octagon" ) 391 set_target_property_all( ${TARGET} ${DIRECTORY_PROPERTY} "${_SHARED_PROXY_PATH}" ) 392 set_target_properties( ${TARGET} 393 PROPERTIES 394 PREFIX "" 395 FOLDER "libraries" # for IDE organization 396 INSTALL_NAME_DIR "" 397 BUILD_WITH_INSTALL_NAME_DIR YES 398 ) 399 endif() 400 401 if( "wxBase" IN_LIST IMPORT_TARGETS OR "wxwidgets::base" IN_LIST IMPORT_TARGETS ) 402 string( APPEND ATTRIBUTES " style=filled" ) 403 endif() 404 405 export_symbol_define( export_symbol "${TARGET}" ) 406 import_symbol_define( import_symbol "${TARGET}" ) 407 408 list( APPEND DEFINES 409 PRIVATE "${export_symbol}" 410 INTERFACE "${import_symbol}" 411 ) 412 413 set( LOPTS 414 PRIVATE 415 $<$<PLATFORM_ID:Darwin>:-undefined dynamic_lookup> 416 ) 417 418 # compute LIBRARIES 419 set( LIBRARIES ) 420 421 foreach( IMPORT ${IMPORT_TARGETS} ) 422 list( APPEND LIBRARIES "${IMPORT}" ) 423 endforeach() 424 425 list( APPEND LIBRARIES ${ADDITIONAL_LIBRARIES} ) 426 427# list( TRANSFORM SOURCES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/" ) 428 429 # Compute compilation options. 430 # Perhaps a another function argument in future to customize this too. 431 set( OPTIONS ) 432 audacity_append_common_compiler_options( OPTIONS NO ) 433 434 organize_source( "${TARGET_ROOT}" "" "${SOURCES}" ) 435 target_sources( ${TARGET} PRIVATE ${SOURCES} ) 436 target_compile_definitions( ${TARGET} PRIVATE ${DEFINES} ) 437 target_compile_options( ${TARGET} ${OPTIONS} ) 438 target_include_directories( ${TARGET} PUBLIC ${TARGET_ROOT} ) 439 440 target_link_options( ${TARGET} PRIVATE ${LOPTS} ) 441 target_link_libraries( ${TARGET} PUBLIC ${LIBRARIES} ) 442 443 if( NOT CMAKE_SYSTEM_NAME MATCHES "Windows" ) 444 add_custom_command( 445 TARGET "${TARGET}" 446 POST_BUILD 447 COMMAND $<IF:$<CONFIG:Debug>,echo,strip> -x $<TARGET_FILE:${TARGET}> 448 ) 449 endif() 450 451 if( NOT REAL_LIBTYPE STREQUAL "MODULE" ) 452 if( CMAKE_SYSTEM_NAME MATCHES "Windows" ) 453 set( REQUIRED_LOCATION "${_EXEDIR}" ) 454 elseif( CMAKE_SYSTEM_NAME MATCHES "Darwin") 455 set( REQUIRED_LOCATION "${_PKGLIB}" ) 456 else() 457 set( REQUIRED_LOCATION "${_DEST}/${_PKGLIB}" ) 458 endif() 459 460 add_custom_command(TARGET ${TARGET} POST_BUILD 461 COMMAND ${CMAKE_COMMAND} -E copy 462 "$<TARGET_FILE:${TARGET}>" 463 "${REQUIRED_LOCATION}/$<TARGET_FILE_NAME:${TARGET}>" 464 ) 465 endif() 466 467 # define an additional interface library target 468 set(INTERFACE_TARGET "${TARGET}-interface") 469 if (NOT REAL_LIBTYPE STREQUAL "MODULE") 470 add_library("${INTERFACE_TARGET}" ALIAS "${TARGET}") 471 else() 472 add_library("${INTERFACE_TARGET}" INTERFACE) 473 foreach(PROP 474 INTERFACE_INCLUDE_DIRECTORIES 475 INTERFACE_COMPILE_DEFINITIONS 476 INTERFACE_LINK_LIBRARIES 477 ) 478 get_target_property( PROPS "${TARGET}" "${PROP}" ) 479 if (PROPS) 480 set_target_properties( 481 "${INTERFACE_TARGET}" 482 PROPERTIES "${PROP}" "${PROPS}" ) 483 endif() 484 endforeach() 485 endif() 486 487 # collect dependency information 488 list( APPEND GRAPH_EDGES "\"${TARGET}\" [${ATTRIBUTES}]" ) 489 if (NOT LIBTYPE STREQUAL "MODULE") 490 list( APPEND GRAPH_EDGES "\"Audacity\" -> \"${TARGET}\"" ) 491 endif () 492 set(ACCESS PUBLIC PRIVATE INTERFACE) 493 foreach( IMPORT ${IMPORT_TARGETS} ) 494 if(IMPORT IN_LIST ACCESS) 495 continue() 496 endif() 497 canonicalize_node_name(IMPORT "${IMPORT}") 498 list( APPEND GRAPH_EDGES "\"${TARGET}\" -> \"${IMPORT}\"" ) 499 endforeach() 500 set( GRAPH_EDGES "${GRAPH_EDGES}" PARENT_SCOPE ) 501endfunction() 502 503# Set up for defining a module target. 504# All modules depend on the application. 505# Pass a name and sources, and a list of other targets. 506# Use the interface compile definitions and include directories of the 507# other targets, and link to them. 508# More defines, and more target libraries (maybe generator expressions) 509# may be given too. 510macro( audacity_module NAME SOURCES IMPORT_TARGETS 511 ADDITIONAL_DEFINES ADDITIONAL_LIBRARIES ) 512 # The extra indirection of a function call from this macro, and 513 # re-assignment of GRAPH_EDGES, is so that a module definition may 514 # call this macro, and it will (correctly) collect edges for the 515 # CMakeLists.txt in the directory above it; but otherwise we take 516 # advantage of function scoping of variables. 517 audacity_module_fn( 518 "${NAME}" 519 "${SOURCES}" 520 "${IMPORT_TARGETS}" 521 "${ADDITIONAL_DEFINES}" 522 "${ADDITIONAL_LIBRARIES}" 523 "MODULE" 524 ) 525 set( GRAPH_EDGES "${GRAPH_EDGES}" PARENT_SCOPE ) 526endmacro() 527 528# Set up for defining a library target. 529# The application depends on all libraries. 530# Pass a name and sources, and a list of other targets. 531# Use the interface compile definitions and include directories of the 532# other targets, and link to them. 533# More defines, and more target libraries (maybe generator expressions) 534# may be given too. 535macro( audacity_library NAME SOURCES IMPORT_TARGETS 536 ADDITIONAL_DEFINES ADDITIONAL_LIBRARIES ) 537 # ditto comment in the previous macro 538 audacity_module_fn( 539 "${NAME}" 540 "${SOURCES}" 541 "${IMPORT_TARGETS}" 542 "${ADDITIONAL_DEFINES}" 543 "${ADDITIONAL_LIBRARIES}" 544 "SHARED" 545 ) 546 set( GRAPH_EDGES "${GRAPH_EDGES}" PARENT_SCOPE ) 547 # Collect list of libraries for the executable to declare dependency on 548 list( APPEND AUDACITY_LIBRARIES "${NAME}" ) 549 set( AUDACITY_LIBRARIES "${AUDACITY_LIBRARIES}" PARENT_SCOPE ) 550endmacro() 551 552# A special macro for header only libraries 553 554macro( audacity_header_only_library NAME SOURCES IMPORT_TARGETS 555 ADDITIONAL_DEFINES ) 556 # ditto comment in the previous macro 557 add_library( ${NAME} INTERFACE ) 558 559 target_include_directories ( ${NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ) 560 target_sources( ${NAME} INTERFACE ${SOURCES}) 561 target_link_libraries( ${NAME} INTERFACE ${IMPORT_TARGETS} ) 562 target_compile_definitions( ${NAME} INTERFACE ${ADDITIONAL_DEFINES} ) 563 564 list( APPEND AUDACITY_LIBRARIES "${NAME}" ) 565 set( AUDACITY_LIBRARIES "${AUDACITY_LIBRARIES}" PARENT_SCOPE ) 566endmacro() 567 568# 569# Add individual library targets 570# 571# Parms: 572# dir directory name within the cmake-proxies directory. 573# (Doesn't HAVE to match the same directory in lib-src, 574# but it usually does.) 575# 576# name suffix for the cmake user options 577# 578# symbol suffix for the "USE_<symbol>" variable that the Audacity 579# target uses to include/exclude functionality. 580# 581# required Determines if the library is required or not. If it is, 582# the user is not given the option of enabling/disabling it. 583# 584# check Determines if local/system checks should be performed here 585# or in the subdirectory config. 586# 587# packages A list of packages required for this target in pkg-config 588# format. 589function( addlib dir name symbol required check ) 590 set( subdir "${CMAKE_SOURCE_DIR}/cmake-proxies/${dir}" ) 591 set( bindir "${CMAKE_BINARY_DIR}/cmake-proxies/${dir}" ) 592 593 # Extract the list of packages from the function args 594 list( SUBLIST ARGV 5 -1 packages ) 595 596 # Define target's name and it's source directory 597 set( TARGET ${dir} ) 598 set( TARGET_ROOT ${libsrc}/${dir} ) 599 600 # Define the option name 601 set( use ${_OPT}use_${name} ) 602 603 # If we're not checking for system or local here, then let the 604 # target config handle the rest. 605 if( NOT check ) 606 add_subdirectory( ${subdir} ${bindir} EXCLUDE_FROM_ALL ) 607 return() 608 endif() 609 610 # If the target isn't required, allow the user to select which one 611 # to use or disable it entirely 612 set( desc "local" ) 613 if( packages ) 614 set( sysopt "system" ) 615 string( PREPEND desc "system (if available), " ) 616 set( default "${${_OPT}lib_preference}" ) 617 else() 618 set( default "local" ) 619 endif() 620 621 if( NOT required ) 622 set( reqopt "off" ) 623 string( APPEND desc ", off" ) 624 endif() 625 626 cmd_option( ${use} 627 "Use ${name} library [${desc}]" 628 "${default}" 629 STRINGS ${sysopt} "local" ${reqopt} 630 ) 631 632 # Bail if the target will not be used 633 if( ${use} STREQUAL "off" ) 634 message( STATUS "========== ${name} disabled ==========" ) 635 636 set( USE_${symbol} OFF CACHE INTERNAL "" FORCE ) 637 638 return() 639 endif() 640 641 # Let the Audacity target know that this library will be used 642 set( USE_${symbol} ON CACHE INTERNAL "" FORCE ) 643 644 if ( TARGET "${TARGET}" ) 645 return() 646 endif() 647 648 message( STATUS "========== Configuring ${name} ==========" ) 649 650 # Check for the system package(s) if the user prefers it 651 if( ${use} STREQUAL "system" ) 652 # Look them up 653 pkg_check_modules( PKG_${TARGET} ${packages} ) 654 655 if( PKG_${TARGET}_FOUND ) 656 message( STATUS "Using '${name}' system library" ) 657 658 # Create the target interface library 659 add_library( ${TARGET} INTERFACE IMPORTED GLOBAL ) 660 661 # Retrieve the package information 662 get_package_interface( PKG_${TARGET} ${TARGET} ) 663 else() 664 find_package( ${packages} QUIET ) 665 666 if( TARGET ${TARGET} ) 667 set( PKG_${TARGET}_FOUND Yes ) 668 endif() 669 endif() 670 671 if( NOT PKG_${TARGET}_FOUND ) 672 if( ${_OPT}obey_system_dependencies ) 673 message( FATAL_ERROR "Failed to find the system package ${name}" ) 674 else() 675 set( ${use} "local" ) 676 set_property( CACHE ${use} PROPERTY VALUE "local" ) 677 endif() 678 endif() 679 endif() 680 681 # User wants the local package or the system one wasn't found 682 if( ${use} STREQUAL "local" ) 683 message( STATUS "Using '${name}' local library" ) 684 685 # Pull in the target config 686 add_subdirectory( ${subdir} ${bindir} EXCLUDE_FROM_ALL ) 687 688 # Get the list of targets defined by that config 689 get_property( targets DIRECTORY "${subdir}" PROPERTY BUILDSYSTEM_TARGETS ) 690 691 # Set the folder (for the IDEs) for each one 692 foreach( target ${targets} ) 693 # Skip interface libraries since they don't have any source to 694 # present in the IDEs 695 get_target_property( type "${target}" TYPE ) 696 if( NOT "${type}" STREQUAL "INTERFACE_LIBRARY" ) 697 set_target_properties( ${target} PROPERTIES FOLDER "lib-src" ) 698 endif() 699 endforeach() 700 endif() 701endfunction() 702 703