Browse Source

macOS/iOS: Add the ability to weak link module frameworks

pull/22/head
Tom Poole 3 years ago
parent
commit
e5cbcd7628
6 changed files with 81 additions and 45 deletions
  1. +9
    -2
      docs/JUCE Module Format.md
  2. +36
    -16
      extras/Build/CMake/JUCEModuleSupport.cmake
  3. +1
    -1
      extras/Projucer/Source/Application/jucer_CommandLine.cpp
  4. +21
    -16
      extras/Projucer/Source/Project/Modules/jucer_Modules.cpp
  5. +10
    -10
      extras/Projucer/Source/Project/Modules/jucer_Modules.h
  6. +4
    -0
      extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h

+ 9
- 2
docs/JUCE Module Format.md View File

@@ -185,11 +185,18 @@ Possible values:
parent folder, which need to be added to a project's header search path parent folder, which need to be added to a project's header search path
- OSXFrameworks - OSXFrameworks
- (Optional) A list (space or comma-separated) of OSX frameworks that are needed
- (Optional) A list (space or comma-separated) of OSX frameworks that are needed by this module
- WeakOSXFrameworks
- (Optional) A list (space or comma-separated) of weak linked OSX frameworks that are needed
by this module by this module
- iOSFrameworks - iOSFrameworks
- (Optional) Like OSXFrameworks, but for iOS targets
- (Optional) A list (space or comma-separated) of iOS frameworks that are needed by this module
- WeakiOSFrameworks
- (Optional) A list (space or comma-separated) of weak linked iOS frameworks that are needed
by this module
- linuxPackages - linuxPackages
- (Optional) A list (space or comma-separated) pkg-config packages that should be used to pass - (Optional) A list (space or comma-separated) pkg-config packages that should be used to pass


+ 36
- 16
extras/Build/CMake/JUCEModuleSupport.cmake View File

@@ -265,22 +265,29 @@ endfunction()


# ================================================================================================== # ==================================================================================================


# Takes a target, a link visibility, and a variable-length list of framework
# names. On macOS, finds the requested frameworks using `find_library` and
# links them. On iOS, links directly with `-framework Name`.
# Takes a target, a link visibility, if it should be a weak link, and a variable-length list of
# framework names. On macOS, for non-weak links, this finds the requested frameworks using
# `find_library`.
function(_juce_link_frameworks target visibility) function(_juce_link_frameworks target visibility)
foreach(framework IN LISTS ARGN)
set(options WEAK)
cmake_parse_arguments(JUCE_LINK_FRAMEWORKS "${options}" "" "" ${ARGN})
foreach(framework IN LISTS JUCE_LINK_FRAMEWORKS_UNPARSED_ARGUMENTS)
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
find_library("juce_found_${framework}" "${framework}" REQUIRED)
target_link_libraries("${target}" "${visibility}" "${juce_found_${framework}}")
if(JUCE_LINK_FRAMEWORKS_WEAK)
set(framework_flags "-weak_framework ${framework}")
else()
find_library("juce_found_${framework}" "${framework}" REQUIRED)
set(framework_flags "${juce_found_${framework}}")
endif()
elseif(CMAKE_SYSTEM_NAME STREQUAL "iOS") elseif(CMAKE_SYSTEM_NAME STREQUAL "iOS")
# CoreServices is only available on iOS 12+, we must link it weakly on earlier platforms # CoreServices is only available on iOS 12+, we must link it weakly on earlier platforms
if((framework STREQUAL "CoreServices") AND (CMAKE_OSX_DEPLOYMENT_TARGET LESS 12.0))
if(JUCE_LINK_FRAMEWORKS_WEAK OR ((framework STREQUAL "CoreServices") AND (CMAKE_OSX_DEPLOYMENT_TARGET LESS 12.0)))
set(framework_flags "-weak_framework ${framework}") set(framework_flags "-weak_framework ${framework}")
else() else()
set(framework_flags "-framework ${framework}") set(framework_flags "-framework ${framework}")
endif() endif()

endif()
if(NOT framework_flags STREQUAL "")
target_link_libraries("${target}" "${visibility}" "${framework_flags}") target_link_libraries("${target}" "${visibility}" "${framework_flags}")
endif() endif()
endforeach() endforeach()
@@ -391,6 +398,11 @@ endfunction()


# ================================================================================================== # ==================================================================================================


function(_juce_remove_empty_list_elements arg)
list(FILTER ${arg} EXCLUDE REGEX "^$")
set(${arg} ${${arg}} PARENT_SCOPE)
endfunction()

function(juce_add_module module_path) function(juce_add_module module_path)
set(one_value_args INSTALL_PATH ALIAS_NAMESPACE) set(one_value_args INSTALL_PATH ALIAS_NAMESPACE)
cmake_parse_arguments(JUCE_ARG "" "${one_value_args}" "" ${ARGN}) cmake_parse_arguments(JUCE_ARG "" "${one_value_args}" "" ${ARGN})
@@ -522,26 +534,34 @@ function(juce_add_module module_path)
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
_juce_get_metadata("${metadata_dict}" OSXFrameworks module_osxframeworks) _juce_get_metadata("${metadata_dict}" OSXFrameworks module_osxframeworks)


_juce_remove_empty_list_elements(module_osxframeworks)
foreach(module_framework IN LISTS module_osxframeworks) foreach(module_framework IN LISTS module_osxframeworks)
if(module_framework STREQUAL "")
continue()
endif()

_juce_link_frameworks("${module_name}" INTERFACE "${module_framework}") _juce_link_frameworks("${module_name}" INTERFACE "${module_framework}")
endforeach() endforeach()


_juce_get_metadata("${metadata_dict}" WeakOSXFrameworks module_weakosxframeworks)

_juce_remove_empty_list_elements(module_weakosxframeworks)
foreach(module_framework IN LISTS module_weakosxframeworks)
_juce_link_frameworks("${module_name}" INTERFACE WEAK "${module_framework}")
endforeach()

_juce_link_libs_from_metadata("${module_name}" "${metadata_dict}" OSXLibs) _juce_link_libs_from_metadata("${module_name}" "${metadata_dict}" OSXLibs)
elseif(CMAKE_SYSTEM_NAME STREQUAL "iOS") elseif(CMAKE_SYSTEM_NAME STREQUAL "iOS")
_juce_get_metadata("${metadata_dict}" iOSFrameworks module_iosframeworks) _juce_get_metadata("${metadata_dict}" iOSFrameworks module_iosframeworks)


_juce_remove_empty_list_elements(module_iosframeworks)
foreach(module_framework IN LISTS module_iosframeworks) foreach(module_framework IN LISTS module_iosframeworks)
if(module_framework STREQUAL "")
continue()
endif()

_juce_link_frameworks("${module_name}" INTERFACE "${module_framework}") _juce_link_frameworks("${module_name}" INTERFACE "${module_framework}")
endforeach() endforeach()


_juce_get_metadata("${metadata_dict}" WeakiOSFrameworks module_weakiosframeworks)

_juce_remove_empty_list_elements(module_weakiosframeworks)
foreach(module_framework IN LISTS module_weakiosframeworks)
_juce_link_frameworks("${module_name}" INTERFACE WEAK "${module_framework}")
endforeach()

_juce_link_libs_from_metadata("${module_name}" "${metadata_dict}" iOSLibs) _juce_link_libs_from_metadata("${module_name}" "${metadata_dict}" iOSLibs)
elseif((CMAKE_SYSTEM_NAME STREQUAL "Linux") OR (CMAKE_SYSTEM_NAME MATCHES ".*BSD")) elseif((CMAKE_SYSTEM_NAME STREQUAL "Linux") OR (CMAKE_SYSTEM_NAME MATCHES ".*BSD"))
_juce_get_metadata("${metadata_dict}" linuxPackages module_linuxpackages) _juce_get_metadata("${metadata_dict}" linuxPackages module_linuxpackages)


+ 1
- 1
extras/Projucer/Source/Application/jucer_CommandLine.cpp View File

@@ -323,7 +323,7 @@ namespace
var moduleInfo (new DynamicObject()); var moduleInfo (new DynamicObject());
moduleInfo.getDynamicObject()->setProperty ("file", getModulePackageName (module)); moduleInfo.getDynamicObject()->setProperty ("file", getModulePackageName (module));
moduleInfo.getDynamicObject()->setProperty ("info", module.moduleInfo.getModuleInfo());
moduleInfo.getDynamicObject()->setProperty ("info", module.moduleDescription.getModuleInfo());
infoList.append (moduleInfo); infoList.append (moduleInfo);
} }
} }


+ 21
- 16
extras/Projucer/Source/Project/Modules/jucer_Modules.cpp View File

@@ -23,7 +23,7 @@
//============================================================================== //==============================================================================
LibraryModule::LibraryModule (const ModuleDescription& d) LibraryModule::LibraryModule (const ModuleDescription& d)
: moduleInfo (d)
: moduleDescription (d)
{ {
} }
@@ -36,15 +36,15 @@ void LibraryModule::writeIncludes (ProjectSaver& projectSaver, OutputStream& out
if (modules.shouldCopyModuleFilesLocally (moduleID)) if (modules.shouldCopyModuleFilesLocally (moduleID))
{ {
auto juceModuleFolder = moduleInfo.getFolder();
auto juceModuleFolder = moduleDescription.getFolder();
auto localModuleFolder = project.getLocalModuleFolder (moduleID); auto localModuleFolder = project.getLocalModuleFolder (moduleID);
localModuleFolder.createDirectory(); localModuleFolder.createDirectory();
projectSaver.copyFolder (juceModuleFolder, localModuleFolder); projectSaver.copyFolder (juceModuleFolder, localModuleFolder);
} }
out << "#include <" << moduleInfo.getModuleFolder().getFileName() << "/"
<< moduleInfo.getHeader().getFileName()
out << "#include <" << moduleDescription.getModuleFolder().getFileName() << "/"
<< moduleDescription.getHeader().getFileName()
<< ">" << newLine; << ">" << newLine;
} }
@@ -71,7 +71,7 @@ void LibraryModule::addSearchPathsToExporter (ProjectExporter& exporter) const
if (moduleLibDir.exists()) if (moduleLibDir.exists())
exporter.addToModuleLibPaths ({ libSubdirPath, moduleRelativePath.getRoot() }); exporter.addToModuleLibPaths ({ libSubdirPath, moduleRelativePath.getRoot() });
auto extraInternalSearchPaths = moduleInfo.getExtraSearchPaths().trim();
auto extraInternalSearchPaths = moduleDescription.getExtraSearchPaths().trim();
if (extraInternalSearchPaths.isNotEmpty()) if (extraInternalSearchPaths.isNotEmpty())
{ {
@@ -84,7 +84,7 @@ void LibraryModule::addSearchPathsToExporter (ProjectExporter& exporter) const
void LibraryModule::addDefinesToExporter (ProjectExporter& exporter) const void LibraryModule::addDefinesToExporter (ProjectExporter& exporter) const
{ {
auto extraDefs = moduleInfo.getPreprocessorDefs().trim();
auto extraDefs = moduleDescription.getPreprocessorDefs().trim();
if (extraDefs.isNotEmpty()) if (extraDefs.isNotEmpty())
exporter.getExporterPreprocessorDefsValue() = exporter.getExporterPreprocessorDefsString() + "\n" + extraDefs; exporter.getExporterPreprocessorDefsValue() = exporter.getExporterPreprocessorDefsString() + "\n" + extraDefs;
@@ -98,7 +98,7 @@ void LibraryModule::addCompileUnitsToExporter (ProjectExporter& exporter, Projec
auto moduleID = getID(); auto moduleID = getID();
auto localModuleFolder = modules.shouldCopyModuleFilesLocally (moduleID) ? project.getLocalModuleFolder (moduleID) auto localModuleFolder = modules.shouldCopyModuleFilesLocally (moduleID) ? project.getLocalModuleFolder (moduleID)
: moduleInfo.getFolder();
: moduleDescription.getFolder();
Array<File> compiled; Array<File> compiled;
findAndAddCompiledUnits (exporter, &projectSaver, compiled); findAndAddCompiledUnits (exporter, &projectSaver, compiled);
@@ -118,6 +118,8 @@ void LibraryModule::addLibsToExporter (ProjectExporter& exporter) const
auto& project = exporter.getProject(); auto& project = exporter.getProject();
auto moduleInfo = moduleDescription.getModuleInfo();
if (exporter.isXcode()) if (exporter.isXcode())
{ {
auto& xcodeExporter = dynamic_cast<XcodeProjectExporter&> (exporter); auto& xcodeExporter = dynamic_cast<XcodeProjectExporter&> (exporter);
@@ -130,26 +132,29 @@ void LibraryModule::addLibsToExporter (ProjectExporter& exporter) const
xcodeExporter.xcodeFrameworks.add ("AudioUnit"); xcodeExporter.xcodeFrameworks.add ("AudioUnit");
} }
auto frameworks = moduleInfo.getModuleInfo() [xcodeExporter.isOSX() ? "OSXFrameworks" : "iOSFrameworks"].toString();
auto frameworks = moduleInfo[xcodeExporter.isOSX() ? "OSXFrameworks" : "iOSFrameworks"].toString();
xcodeExporter.xcodeFrameworks.addTokens (frameworks, ", ", {}); xcodeExporter.xcodeFrameworks.addTokens (frameworks, ", ", {});
parseAndAddLibsToList (xcodeExporter.xcodeLibs, moduleInfo.getModuleInfo() [exporter.isOSX() ? "OSXLibs" : "iOSLibs"].toString());
auto weakFrameworks = moduleInfo[xcodeExporter.isOSX() ? "WeakOSXFrameworks" : "WeakiOSFrameworks"].toString();
xcodeExporter.xcodeWeakFrameworks.addTokens (weakFrameworks, ", ", {});
parseAndAddLibsToList (xcodeExporter.xcodeLibs, moduleInfo[exporter.isOSX() ? "OSXLibs" : "iOSLibs"].toString());
} }
else if (exporter.isLinux()) else if (exporter.isLinux())
{ {
parseAndAddLibsToList (exporter.linuxLibs, moduleInfo.getModuleInfo() ["linuxLibs"].toString());
parseAndAddLibsToList (exporter.linuxPackages, moduleInfo.getModuleInfo() ["linuxPackages"].toString());
parseAndAddLibsToList (exporter.linuxLibs, moduleInfo["linuxLibs"].toString());
parseAndAddLibsToList (exporter.linuxPackages, moduleInfo["linuxPackages"].toString());
} }
else if (exporter.isWindows()) else if (exporter.isWindows())
{ {
if (exporter.isCodeBlocks()) if (exporter.isCodeBlocks())
parseAndAddLibsToList (exporter.mingwLibs, moduleInfo.getModuleInfo() ["mingwLibs"].toString());
parseAndAddLibsToList (exporter.mingwLibs, moduleInfo["mingwLibs"].toString());
else else
parseAndAddLibsToList (exporter.windowsLibs, moduleInfo.getModuleInfo() ["windowsLibs"].toString());
parseAndAddLibsToList (exporter.windowsLibs, moduleInfo["windowsLibs"].toString());
} }
else if (exporter.isAndroid()) else if (exporter.isAndroid())
{ {
parseAndAddLibsToList (exporter.androidLibs, moduleInfo.getModuleInfo() ["androidLibs"].toString());
parseAndAddLibsToList (exporter.androidLibs, moduleInfo["androidLibs"].toString());
} }
} }
@@ -163,7 +168,7 @@ void LibraryModule::addSettingsForModuleToExporter (ProjectExporter& exporter, P
void LibraryModule::getConfigFlags (Project& project, OwnedArray<Project::ConfigFlag>& flags) const void LibraryModule::getConfigFlags (Project& project, OwnedArray<Project::ConfigFlag>& flags) const
{ {
auto header = moduleInfo.getHeader();
auto header = moduleDescription.getHeader();
jassert (header.exists()); jassert (header.exists());
StringArray lines; StringArray lines;
@@ -348,7 +353,7 @@ void LibraryModule::addBrowseableCode (ProjectExporter& exporter, const Array<Fi
auto sourceGroup = Project::Item::createGroup (exporter.getProject(), getID(), "__mainsourcegroup" + getID(), false); auto sourceGroup = Project::Item::createGroup (exporter.getProject(), getID(), "__mainsourcegroup" + getID(), false);
auto moduleFromProject = exporter.getModuleFolderRelativeToProject (getID()); auto moduleFromProject = exporter.getModuleFolderRelativeToProject (getID());
auto moduleHeader = moduleInfo.getHeader();
auto moduleHeader = moduleDescription.getHeader();
auto& project = exporter.getProject(); auto& project = exporter.getProject();


+ 10
- 10
extras/Projucer/Source/Project/Modules/jucer_Modules.h View File

@@ -29,16 +29,16 @@ class LibraryModule
public: public:
LibraryModule (const ModuleDescription&); LibraryModule (const ModuleDescription&);
bool isValid() const { return moduleInfo.isValid(); }
String getID() const { return moduleInfo.getID(); }
String getVendor() const { return moduleInfo.getVendor(); }
String getVersion() const { return moduleInfo.getVersion(); }
String getName() const { return moduleInfo.getName(); }
String getDescription() const { return moduleInfo.getDescription(); }
String getLicense() const { return moduleInfo.getLicense(); }
String getMinimumCppStandard() const { return moduleInfo.getMinimumCppStandard(); }
bool isValid() const { return moduleDescription.isValid(); }
String getID() const { return moduleDescription.getID(); }
String getVendor() const { return moduleDescription.getVendor(); }
String getVersion() const { return moduleDescription.getVersion(); }
String getName() const { return moduleDescription.getName(); }
String getDescription() const { return moduleDescription.getDescription(); }
String getLicense() const { return moduleDescription.getLicense(); }
String getMinimumCppStandard() const { return moduleDescription.getMinimumCppStandard(); }
File getFolder() const { return moduleInfo.getFolder(); }
File getFolder() const { return moduleDescription.getFolder(); }
void writeIncludes (ProjectSaver&, OutputStream&); void writeIncludes (ProjectSaver&, OutputStream&);
void addSettingsForModuleToExporter (ProjectExporter&, ProjectSaver&) const; void addSettingsForModuleToExporter (ProjectExporter&, ProjectSaver&) const;
@@ -61,7 +61,7 @@ public:
build_tools::ProjectType::Target::Type forTarget = build_tools::ProjectType::Target::Type forTarget =
build_tools::ProjectType::Target::unspecified) const; build_tools::ProjectType::Target::unspecified) const;
ModuleDescription moduleInfo;
ModuleDescription moduleDescription;
private: private:
void addSearchPathsToExporter (ProjectExporter&) const; void addSearchPathsToExporter (ProjectExporter&) const;


+ 4
- 0
extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h View File

@@ -1696,6 +1696,9 @@ public:
StringArray linkerFlags, librarySearchPaths; StringArray linkerFlags, librarySearchPaths;
getLinkerSettings (config, linkerFlags, librarySearchPaths); getLinkerSettings (config, linkerFlags, librarySearchPaths);
for (const auto& weakFramework : owner.xcodeWeakFrameworks)
linkerFlags.add ("-weak_framework " + weakFramework);
if (linkerFlags.size() > 0) if (linkerFlags.size() > 0)
s.set ("OTHER_LDFLAGS", linkerFlags.joinIntoString (" ").quoted()); s.set ("OTHER_LDFLAGS", linkerFlags.joinIntoString (" ").quoted());
@@ -2054,6 +2057,7 @@ public:
}; };
mutable StringArray xcodeFrameworks; mutable StringArray xcodeFrameworks;
mutable StringArray xcodeWeakFrameworks;
StringArray xcodeLibs; StringArray xcodeLibs;
private: private:


Loading…
Cancel
Save