2021-08-11 11:06:46 +03:00
using System ;
2016-04-21 15:57:02 +03:00
using System.Collections.Generic ;
using System.IO ;
2019-10-14 17:18:46 +03:00
using System.Linq ;
2016-04-21 15:57:02 +03:00
using System.Text ;
using Xamarin.Bundler ;
namespace Xamarin.Utils
{
public class CompilerFlags
{
public Application Application { get { return Target . App ; } }
public Target Target ;
public HashSet < string > Frameworks ; // if a file, "-F /path/to/X --framework X" and added to Inputs, otherwise "--framework X".
public HashSet < string > WeakFrameworks ;
public HashSet < string > LinkWithLibraries ; // X, added to Inputs
public HashSet < string > ForceLoadLibraries ; // -force_load X, added to Inputs
2019-10-14 17:18:46 +03:00
public HashSet < string [ ] > OtherFlags ; // X
2019-06-07 21:41:57 +03:00
public List < string > InitialOtherFlags ; // same as OtherFlags, only that they're the first argument(s) to clang (because order matters!). This is a list to preserve order (fifo).
2016-04-21 15:57:02 +03:00
public HashSet < string > Defines ; // -DX
public HashSet < string > UnresolvedSymbols ; // -u X
2017-01-25 17:06:56 +03:00
public HashSet < string > SourceFiles ; // X, added to Inputs
2016-04-21 15:57:02 +03:00
// Here we store a list of all the file-system based inputs
// to the compiler. This is used when determining if the
// compiler needs to be called in the first place (dependency
// tracking).
public List < string > Inputs ;
2017-01-25 19:30:04 +03:00
public CompilerFlags ( Target target )
{
if ( target = = null )
throw new ArgumentNullException ( nameof ( target ) ) ;
this . Target = target ;
}
2017-01-25 15:07:37 +03:00
public HashSet < string > AllLibraries {
get {
var rv = new HashSet < string > ( ) ;
if ( LinkWithLibraries ! = null )
rv . UnionWith ( LinkWithLibraries ) ;
if ( ForceLoadLibraries ! = null )
rv . UnionWith ( ForceLoadLibraries ) ;
return rv ;
}
}
2022-05-03 11:53:45 +03:00
public void ReferenceSymbols ( IEnumerable < Symbol > symbols , Abi abi )
2017-01-18 12:22:53 +03:00
{
if ( UnresolvedSymbols = = null )
UnresolvedSymbols = new HashSet < string > ( ) ;
2022-05-03 11:53:45 +03:00
foreach ( var symbol in symbols ) {
if ( symbol . ValidAbis . HasValue & & ( symbol . ValidAbis . Value & abi ) = = 0 )
continue ;
2017-08-24 10:42:08 +03:00
UnresolvedSymbols . Add ( symbol . Prefix + symbol . Name ) ;
2022-05-03 11:53:45 +03:00
}
2017-01-18 12:22:53 +03:00
}
2016-04-21 15:57:02 +03:00
public void AddDefine ( string define )
{
if ( Defines = = null )
Defines = new HashSet < string > ( ) ;
Defines . Add ( define ) ;
}
public void AddLinkWith ( string library , bool force_load = false )
{
if ( LinkWithLibraries = = null )
LinkWithLibraries = new HashSet < string > ( ) ;
if ( ForceLoadLibraries = = null )
ForceLoadLibraries = new HashSet < string > ( ) ;
if ( force_load ) {
ForceLoadLibraries . Add ( library ) ;
} else {
LinkWithLibraries . Add ( library ) ;
}
}
public void AddLinkWith ( IEnumerable < string > libraries , bool force_load = false )
{
if ( libraries = = null )
return ;
foreach ( var lib in libraries )
AddLinkWith ( lib , force_load ) ;
}
2017-01-25 17:06:56 +03:00
public void AddSourceFile ( string file )
{
if ( SourceFiles = = null )
SourceFiles = new HashSet < string > ( ) ;
SourceFiles . Add ( file ) ;
}
2018-06-28 15:49:22 +03:00
public void AddStandardCppLibrary ( )
{
if ( Driver . XcodeVersion . Major < 10 )
return ;
// Xcode 10 doesn't ship with libstdc++, so use libc++ instead.
AddOtherFlag ( "-stdlib=libc++" ) ;
}
2019-06-07 21:41:57 +03:00
public void AddOtherInitialFlag ( string flag )
{
if ( InitialOtherFlags = = null )
InitialOtherFlags = new List < string > ( ) ;
InitialOtherFlags . Add ( flag ) ;
}
2019-10-14 17:18:46 +03:00
public void AddOtherFlag ( IList < string > flags )
2016-04-21 15:57:02 +03:00
{
2019-10-14 17:18:46 +03:00
if ( flags = = null )
2019-05-09 19:43:39 +03:00
return ;
2019-10-14 17:18:46 +03:00
AddOtherFlag ( ( string [ ] ) flags . ToArray ( ) ) ;
2016-04-21 15:57:02 +03:00
}
2019-10-14 17:18:46 +03:00
public void AddOtherFlag ( params string [ ] flags )
2016-04-21 15:57:02 +03:00
{
2019-10-14 17:18:46 +03:00
if ( flags = = null | | flags . Length = = 0 )
2016-04-21 15:57:02 +03:00
return ;
if ( OtherFlags = = null )
2019-10-14 17:18:46 +03:00
OtherFlags = new HashSet < string [ ] > ( ) ;
OtherFlags . Add ( flags ) ;
2016-04-21 15:57:02 +03:00
}
public void LinkWithMono ( )
{
2017-01-24 21:08:15 +03:00
var mode = Target . App . LibMonoLinkMode ;
switch ( mode ) {
case AssemblyBuildTarget . DynamicLibrary :
case AssemblyBuildTarget . StaticObject :
AddLinkWith ( Application . GetLibMono ( mode ) ) ;
break ;
case AssemblyBuildTarget . Framework :
AddFramework ( Application . GetLibMono ( mode ) ) ;
break ;
default :
2020-01-31 23:02:52 +03:00
throw ErrorHelper . CreateError ( 100 , Errors . MT0100 , mode ) ;
2016-04-21 15:57:02 +03:00
}
2017-04-10 07:52:00 +03:00
AddOtherFlag ( "-lz" ) ;
AddOtherFlag ( "-liconv" ) ;
2016-04-21 15:57:02 +03:00
}
public void LinkWithXamarin ( )
{
2017-01-24 21:08:15 +03:00
var mode = Target . App . LibXamarinLinkMode ;
switch ( mode ) {
case AssemblyBuildTarget . DynamicLibrary :
case AssemblyBuildTarget . StaticObject :
AddLinkWith ( Application . GetLibXamarin ( mode ) ) ;
break ;
case AssemblyBuildTarget . Framework :
AddFramework ( Application . GetLibXamarin ( mode ) ) ;
break ;
default :
2020-01-31 23:02:52 +03:00
throw ErrorHelper . CreateError ( 100 , Errors . MT0100 , mode ) ;
2017-01-24 21:08:15 +03:00
}
2016-04-21 15:57:02 +03:00
AddFramework ( "Foundation" ) ;
AddOtherFlag ( "-lz" ) ;
2017-04-10 07:52:43 +03:00
if ( Application . Platform ! = ApplePlatform . WatchOS & & Application . Platform ! = ApplePlatform . TVOS )
2019-01-31 13:18:29 +03:00
AddFramework ( "CFNetwork" ) ; // required by xamarin_start_wwan
2016-04-21 15:57:02 +03:00
}
public void AddFramework ( string framework )
{
if ( Frameworks = = null )
Frameworks = new HashSet < string > ( ) ;
Frameworks . Add ( framework ) ;
}
public void AddFrameworks ( IEnumerable < string > frameworks , IEnumerable < string > weak_frameworks )
{
if ( frameworks ! = null ) {
if ( Frameworks = = null )
Frameworks = new HashSet < string > ( ) ;
Frameworks . UnionWith ( frameworks ) ;
}
if ( weak_frameworks ! = null ) {
if ( WeakFrameworks = = null )
WeakFrameworks = new HashSet < string > ( ) ;
WeakFrameworks . UnionWith ( weak_frameworks ) ;
}
}
public void Prepare ( )
{
// Check for system frameworks that are only available in newer iOS versions,
// (newer than the deployment target), in which case those need to be weakly linked.
if ( Frameworks ! = null ) {
if ( WeakFrameworks = = null )
WeakFrameworks = new HashSet < string > ( ) ;
foreach ( var fwk in Frameworks ) {
2016-10-14 13:34:35 +03:00
if ( ! fwk . EndsWith ( ".framework" , StringComparison . Ordinal ) ) {
2016-04-21 15:57:02 +03:00
var add_to = WeakFrameworks ;
2016-12-23 20:50:35 +03:00
var framework = Driver . GetFrameworks ( Application ) . Find ( fwk ) ;
2016-04-21 15:57:02 +03:00
if ( framework ! = null ) {
2016-12-23 20:50:35 +03:00
if ( framework . Version > Application . SdkVersion )
2016-04-21 15:57:02 +03:00
continue ;
add_to = Application . DeploymentTarget > = framework . Version ? Frameworks : WeakFrameworks ;
}
add_to . Add ( fwk ) ;
} else {
// believe what we got about user frameworks.
}
}
// Make sure frameworks aren't duplicated, favoring any weak frameworks.
Frameworks . ExceptWith ( WeakFrameworks ) ;
}
// force_load libraries take precedence, so remove the libraries
// we need to force load from the list of libraries we just load.
if ( LinkWithLibraries ! = null )
LinkWithLibraries . ExceptWith ( ForceLoadLibraries ) ;
}
void AddInput ( string file )
{
if ( Inputs = = null )
return ;
Inputs . Add ( file ) ;
}
2019-10-14 17:18:46 +03:00
public void WriteArguments ( IList < string > args )
2016-04-21 15:57:02 +03:00
{
Prepare ( ) ;
2019-06-07 21:41:57 +03:00
if ( InitialOtherFlags ! = null ) {
var idx = 0 ;
foreach ( var flag in InitialOtherFlags ) {
args . Insert ( idx , flag ) ;
idx + + ;
}
}
2016-04-21 15:57:02 +03:00
ProcessFrameworksForArguments ( args ) ;
if ( LinkWithLibraries ! = null ) {
foreach ( var lib in LinkWithLibraries ) {
2019-10-14 17:18:46 +03:00
args . Add ( lib ) ;
2016-04-21 15:57:02 +03:00
AddInput ( lib ) ;
}
}
if ( ForceLoadLibraries ! = null ) {
foreach ( var lib in ForceLoadLibraries ) {
2019-10-14 17:18:46 +03:00
args . Add ( "-force_load" ) ;
args . Add ( lib ) ;
2016-04-21 15:57:02 +03:00
AddInput ( lib ) ;
}
}
if ( OtherFlags ! = null ) {
2019-10-14 17:18:46 +03:00
foreach ( var flags in OtherFlags ) {
foreach ( var flag in flags )
args . Add ( flag ) ;
}
2016-04-21 15:57:02 +03:00
}
if ( Defines ! = null ) {
2019-10-14 17:18:46 +03:00
foreach ( var define in Defines ) {
args . Add ( "-D" ) ;
args . Add ( define ) ;
}
2016-04-21 15:57:02 +03:00
}
if ( UnresolvedSymbols ! = null ) {
2019-10-14 17:18:46 +03:00
foreach ( var symbol in UnresolvedSymbols ) {
args . Add ( "-u" ) ;
args . Add ( symbol ) ;
}
2016-04-21 15:57:02 +03:00
}
2017-01-25 17:06:56 +03:00
if ( SourceFiles ! = null ) {
foreach ( var src in SourceFiles ) {
2019-10-14 17:18:46 +03:00
args . Add ( src ) ;
2017-01-25 17:06:56 +03:00
AddInput ( src ) ;
}
}
2016-04-21 15:57:02 +03:00
}
2019-10-14 17:18:46 +03:00
void ProcessFrameworksForArguments ( IList < string > args )
2016-04-21 15:57:02 +03:00
{
bool any_user_framework = false ;
if ( Frameworks ! = null ) {
foreach ( var fw in Frameworks )
ProcessFrameworkForArguments ( args , fw , false , ref any_user_framework ) ;
}
if ( WeakFrameworks ! = null ) {
foreach ( var fw in WeakFrameworks )
ProcessFrameworkForArguments ( args , fw , true , ref any_user_framework ) ;
}
if ( any_user_framework ) {
2019-10-14 17:18:46 +03:00
args . Add ( "-Xlinker" ) ;
args . Add ( "-rpath" ) ;
args . Add ( "-Xlinker" ) ;
2020-12-17 20:53:16 +03:00
switch ( Application . Platform ) {
case ApplePlatform . iOS :
case ApplePlatform . TVOS :
case ApplePlatform . WatchOS :
args . Add ( "@executable_path/Frameworks" ) ;
break ;
case ApplePlatform . MacCatalyst :
case ApplePlatform . MacOSX :
args . Add ( "@executable_path/../Frameworks" ) ;
break ;
default :
throw ErrorHelper . CreateError ( 71 , Errors . MX0071 , Application . Platform , Application . ProductName ) ;
}
2019-10-14 17:18:46 +03:00
if ( Application . IsExtension ) {
args . Add ( "-Xlinker" ) ;
args . Add ( "-rpath" ) ;
args . Add ( "-Xlinker" ) ;
args . Add ( "@executable_path/../../Frameworks" ) ;
}
2016-04-21 15:57:02 +03:00
}
2017-01-24 22:24:32 +03:00
2017-04-28 17:10:20 +03:00
if ( Application . HasAnyDynamicLibraries ) {
2019-10-14 17:18:46 +03:00
args . Add ( "-Xlinker" ) ;
args . Add ( "-rpath" ) ;
args . Add ( "-Xlinker" ) ;
args . Add ( "@executable_path/" ) ;
if ( Application . IsExtension ) {
args . Add ( "-Xlinker" ) ;
args . Add ( "-rpath" ) ;
args . Add ( "-Xlinker" ) ;
args . Add ( "@executable_path/../.." ) ;
}
2017-04-28 17:10:20 +03:00
}
2016-04-21 15:57:02 +03:00
}
2019-10-14 17:18:46 +03:00
void ProcessFrameworkForArguments ( IList < string > args , string fw , bool is_weak , ref bool any_user_framework )
2016-04-21 15:57:02 +03:00
{
var name = Path . GetFileNameWithoutExtension ( fw ) ;
2016-10-14 13:34:35 +03:00
if ( fw . EndsWith ( ".framework" , StringComparison . Ordinal ) ) {
2016-04-21 15:57:02 +03:00
// user framework, we need to pass -F to the linker so that the linker finds the user framework.
any_user_framework = true ;
AddInput ( Path . Combine ( fw , name ) ) ;
2019-10-14 17:18:46 +03:00
args . Add ( "-F" ) ;
args . Add ( Path . GetDirectoryName ( fw ) ) ;
2016-04-21 15:57:02 +03:00
}
2019-10-14 17:18:46 +03:00
args . Add ( is_weak ? "-weak_framework" : "-framework" ) ;
args . Add ( name ) ;
2016-04-21 15:57:02 +03:00
}
2019-10-14 17:18:46 +03:00
public string [ ] ToArray ( )
2016-04-21 15:57:02 +03:00
{
2019-10-14 17:18:46 +03:00
var args = new List < string > ( ) ;
2016-04-21 15:57:02 +03:00
WriteArguments ( args ) ;
2019-10-14 17:18:46 +03:00
return args . ToArray ( ) ;
}
public override string ToString ( )
{
return string . Join ( " " , ToArray ( ) ) ;
2016-04-21 15:57:02 +03:00
}
2017-01-25 18:38:24 +03:00
public void PopulateInputs ( )
{
2019-10-14 17:18:46 +03:00
var args = new List < string > ( ) ;
2017-01-25 18:38:24 +03:00
Inputs = new List < string > ( ) ;
WriteArguments ( args ) ;
}
2016-04-21 15:57:02 +03:00
}
}