Merge pull request #620 from mono/merge-objc

Merge objc branch into master
This commit is contained in:
Chris Hamons 2018-03-16 12:54:00 -05:00 коммит произвёл GitHub
Родитель fdf7296329 c14cd916e6
Коммит b56e22dd56
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
45 изменённых файлов: 2106 добавлений и 1395 удалений

Просмотреть файл

@ -9,12 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "managed-generic", "tests\ma
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "managed-pcl", "tests\managed\pcl\managed-pcl.csproj", "{43B5C8AC-74C4-4EB4-AF2D-C62E36F41379}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "managed-android", "tests\managed\android\managed-android.csproj", "{10E2D025-DED3-490D-8EC6-E99B30FE3E4F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoEmbeddinator4000.Tests", "tests\MonoEmbeddinator4000.Tests\MonoEmbeddinator4000.Tests.csproj", "{8B817EDA-6575-4C17-8255-85652BDD1366}"
EndProject
Project("{E46AB94E-5081-B7E4-99F8-4206054E886C}") = "Embeddinator-4000", "build\projects\Embeddinator-4000.csproj", "{509699E3-3C25-23AD-E543-37A8D1B13353}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dependencies", "dependencies", "{7B2816C2-7370-43B2-820E-FC9C798429BB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Android.Tools", "build\projects\Xamarin.Android.Tools.csproj", "{83A10A50-EF0D-C64A-B801-5EA8242DE8B2}"
@ -35,29 +31,35 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CppSharp.Parser", "build\pr
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CppSharp.Runtime", "build\projects\CppSharp.Runtime.csproj", "{189FF169-0498-10BC-2DCA-F5401922F0C7}"
EndProject
Project("{f2a71f9b-5d33-465a-a702-920d77279786}") = "fsharp-android", "tests\managed\fsharp-android\fsharp-android.fsproj", "{558BCEC3-1B1F-4DEC-AF4C-47B404A05DE6}"
EndProject
Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "managedwarn", "tests\managedwarn\managedwarn.csproj", "{39EC3FCA-104C-48DA-8B08-18A11148B8F7}"
EndProject
Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "objcgentest", "tests\objcgentest\objcgentest.csproj", "{DEAAD0EA-0FC2-427A-8B7A-173872FD3629}"
EndProject
Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "leaktest", "tests\leaktest\leaktest.csproj", "{44509EA7-2580-46DE-9557-6AA3B64C1F6B}"
EndProject
Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "managed-ios", "tests\managed\ios\managed-ios.csproj", "{7222DF15-4E26-417D-8B5A-5BD9F1006219}"
EndProject
Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "managed-macos-system", "tests\managed\macos-system\managed-macos-system.csproj", "{5E0CB07E-E4DF-4590-9FF4-C78A92A2D230}"
EndProject
Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "managed-macos-full", "tests\managed\macos-full\managed-macos-full.csproj", "{3B06BDD0-46A5-4362-85BE-3EB7C438D58C}"
EndProject
Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "managed-macos-modern", "tests\managed\macos-modern\managed-macos-modern.csproj", "{22434C3A-ED76-4769-A384-5F48ED66EE75}"
EndProject
Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "managed-netstandard", "tests\managed\netstandard\managed-netstandard.csproj", "{76C06121-9565-438F-A750-024641D9CDF2}"
EndProject
Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "objcgen", "objcgen\objcgen.csproj", "{4D0EB624-B2C9-4484-BA73-BFD5653BF0F6}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "managed-netstandard", "tests\managed\netstandard\managed-netstandard.csproj", "{76C06121-9565-438F-A750-024641D9CDF2}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "fsharp-shared", "tests\managed\fsharp-shared\fsharp-shared.shproj", "{B46AC5CA-D13A-4F82-8A83-76B32F2F74EF}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "fsharp-generic", "tests\managed\fsharp-generic\fsharp-generic.fsproj", "{1D70C6B6-B63D-49F3-AC02-E6F93BAA4377}"
Project("{f2a71f9b-5d33-465a-a702-920d77279786}") = "fsharp-generic", "tests\managed\fsharp-generic\fsharp-generic.fsproj", "{1D70C6B6-B63D-49F3-AC02-E6F93BAA4377}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "managedwarn", "tests\managedwarn\managedwarn.csproj", "{73C4FAF0-C37A-4CEE-A3F3-B1F80748D5B2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "objcgentest", "tests\objcgentest\objcgentest.csproj", "{076A871B-0C13-47D8-8923-B9242995BFF8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "leaktest", "tests\leaktest\leaktest.csproj", "{33D1E7E3-A123-43F0-B047-163C6E75D3BF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "managed-ios", "tests\managed\ios\managed-ios.csproj", "{0D7BFE1A-730A-48B0-A99A-F6E6A6C134DC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "managed-macos-system", "tests\managed\macos-system\managed-macos-system.csproj", "{73636472-C245-4F57-9229-1DB22D643DFD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "managed-macos-full", "tests\managed\macos-full\managed-macos-full.csproj", "{8846BDE1-3377-4BED-BAB4-820F5CDF6D37}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "managed-macos-modern", "tests\managed\macos-modern\managed-macos-modern.csproj", "{1A66B3FB-3482-4981-B3E9-2658A8773E9A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "managed-tvos", "tests\managed\tvos\managed-tvos.csproj", "{C5EBF917-C812-4D46-B7EE-0960FEB51081}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Embeddinator-4000", "build\projects\Embeddinator-4000.csproj", "{E46AB94E-5081-B7E4-99F8-4206054E886C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "objcgen", "objcgen\objcgen.csproj", "{C166803B-011F-4EAF-B8C2-D7DBBA3CF1EC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "managed-android", "tests\managed\android\managed-android.csproj", "{10E2D025-DED3-490D-8EC6-E99B30FE3E4F}"
EndProject
Project("{f2a71f9b-5d33-465a-a702-920d77279786}") = "fsharp-android", "tests\managed\fsharp-android\fsharp-android.fsproj", "{558BCEC3-1B1F-4DEC-AF4C-47B404A05DE6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -73,18 +75,10 @@ Global
{43B5C8AC-74C4-4EB4-AF2D-C62E36F41379}.Debug|x86.Build.0 = Debug|Any CPU
{43B5C8AC-74C4-4EB4-AF2D-C62E36F41379}.Release|x86.ActiveCfg = Release|Any CPU
{43B5C8AC-74C4-4EB4-AF2D-C62E36F41379}.Release|x86.Build.0 = Release|Any CPU
{10E2D025-DED3-490D-8EC6-E99B30FE3E4F}.Debug|x86.ActiveCfg = Debug|Any CPU
{10E2D025-DED3-490D-8EC6-E99B30FE3E4F}.Debug|x86.Build.0 = Debug|Any CPU
{10E2D025-DED3-490D-8EC6-E99B30FE3E4F}.Release|x86.ActiveCfg = Release|Any CPU
{10E2D025-DED3-490D-8EC6-E99B30FE3E4F}.Release|x86.Build.0 = Release|Any CPU
{8B817EDA-6575-4C17-8255-85652BDD1366}.Debug|x86.ActiveCfg = Debug|x86
{8B817EDA-6575-4C17-8255-85652BDD1366}.Debug|x86.Build.0 = Debug|x86
{8B817EDA-6575-4C17-8255-85652BDD1366}.Release|x86.ActiveCfg = Release|x86
{8B817EDA-6575-4C17-8255-85652BDD1366}.Release|x86.Build.0 = Release|x86
{509699E3-3C25-23AD-E543-37A8D1B13353}.Debug|x86.ActiveCfg = Debug|x86
{509699E3-3C25-23AD-E543-37A8D1B13353}.Debug|x86.Build.0 = Debug|x86
{509699E3-3C25-23AD-E543-37A8D1B13353}.Release|x86.ActiveCfg = Release|x86
{509699E3-3C25-23AD-E543-37A8D1B13353}.Release|x86.Build.0 = Release|x86
{83A10A50-EF0D-C64A-B801-5EA8242DE8B2}.Debug|x86.ActiveCfg = Debug|x86
{83A10A50-EF0D-C64A-B801-5EA8242DE8B2}.Debug|x86.Build.0 = Debug|x86
{83A10A50-EF0D-C64A-B801-5EA8242DE8B2}.Release|x86.ActiveCfg = Release|x86
@ -121,52 +115,63 @@ Global
{189FF169-0498-10BC-2DCA-F5401922F0C7}.Debug|x86.Build.0 = Debug|x86
{189FF169-0498-10BC-2DCA-F5401922F0C7}.Release|x86.ActiveCfg = Release|x86
{189FF169-0498-10BC-2DCA-F5401922F0C7}.Release|x86.Build.0 = Release|x86
{558BCEC3-1B1F-4DEC-AF4C-47B404A05DE6}.Debug|x86.ActiveCfg = Debug|Any CPU
{558BCEC3-1B1F-4DEC-AF4C-47B404A05DE6}.Debug|x86.Build.0 = Debug|Any CPU
{558BCEC3-1B1F-4DEC-AF4C-47B404A05DE6}.Release|x86.ActiveCfg = Release|Any CPU
{558BCEC3-1B1F-4DEC-AF4C-47B404A05DE6}.Release|x86.Build.0 = Release|Any CPU
{39EC3FCA-104C-48DA-8B08-18A11148B8F7}.Debug|x86.ActiveCfg = Debug|Any CPU
{39EC3FCA-104C-48DA-8B08-18A11148B8F7}.Debug|x86.Build.0 = Debug|Any CPU
{39EC3FCA-104C-48DA-8B08-18A11148B8F7}.Release|x86.ActiveCfg = Release|Any CPU
{39EC3FCA-104C-48DA-8B08-18A11148B8F7}.Release|x86.Build.0 = Release|Any CPU
{DEAAD0EA-0FC2-427A-8B7A-173872FD3629}.Debug|x86.ActiveCfg = Debug|x86
{DEAAD0EA-0FC2-427A-8B7A-173872FD3629}.Debug|x86.Build.0 = Debug|x86
{DEAAD0EA-0FC2-427A-8B7A-173872FD3629}.Release|x86.ActiveCfg = Release|x86
{DEAAD0EA-0FC2-427A-8B7A-173872FD3629}.Release|x86.Build.0 = Release|x86
{44509EA7-2580-46DE-9557-6AA3B64C1F6B}.Debug|x86.ActiveCfg = Debug|x86
{44509EA7-2580-46DE-9557-6AA3B64C1F6B}.Debug|x86.Build.0 = Debug|x86
{44509EA7-2580-46DE-9557-6AA3B64C1F6B}.Release|x86.ActiveCfg = Release|x86
{44509EA7-2580-46DE-9557-6AA3B64C1F6B}.Release|x86.Build.0 = Release|x86
{7222DF15-4E26-417D-8B5A-5BD9F1006219}.Debug|x86.ActiveCfg = Debug|x86
{7222DF15-4E26-417D-8B5A-5BD9F1006219}.Debug|x86.Build.0 = Debug|x86
{7222DF15-4E26-417D-8B5A-5BD9F1006219}.Release|x86.ActiveCfg = Release|x86
{7222DF15-4E26-417D-8B5A-5BD9F1006219}.Release|x86.Build.0 = Release|x86
{5E0CB07E-E4DF-4590-9FF4-C78A92A2D230}.Debug|x86.ActiveCfg = Debug|x86
{5E0CB07E-E4DF-4590-9FF4-C78A92A2D230}.Debug|x86.Build.0 = Debug|x86
{5E0CB07E-E4DF-4590-9FF4-C78A92A2D230}.Release|x86.ActiveCfg = Release|x86
{5E0CB07E-E4DF-4590-9FF4-C78A92A2D230}.Release|x86.Build.0 = Release|x86
{3B06BDD0-46A5-4362-85BE-3EB7C438D58C}.Debug|x86.ActiveCfg = Debug|x86
{3B06BDD0-46A5-4362-85BE-3EB7C438D58C}.Debug|x86.Build.0 = Debug|x86
{3B06BDD0-46A5-4362-85BE-3EB7C438D58C}.Release|x86.ActiveCfg = Release|x86
{3B06BDD0-46A5-4362-85BE-3EB7C438D58C}.Release|x86.Build.0 = Release|x86
{22434C3A-ED76-4769-A384-5F48ED66EE75}.Debug|x86.ActiveCfg = Debug|x86
{22434C3A-ED76-4769-A384-5F48ED66EE75}.Debug|x86.Build.0 = Debug|x86
{22434C3A-ED76-4769-A384-5F48ED66EE75}.Release|x86.ActiveCfg = Release|x86
{22434C3A-ED76-4769-A384-5F48ED66EE75}.Release|x86.Build.0 = Release|x86
{76C06121-9565-438F-A750-024641D9CDF2}.Debug|x86.ActiveCfg = Debug|Any CPU
{76C06121-9565-438F-A750-024641D9CDF2}.Debug|x86.Build.0 = Debug|Any CPU
{76C06121-9565-438F-A750-024641D9CDF2}.Release|x86.ActiveCfg = Release|Any CPU
{76C06121-9565-438F-A750-024641D9CDF2}.Release|x86.Build.0 = Release|Any CPU
{4D0EB624-B2C9-4484-BA73-BFD5653BF0F6}.Debug|x86.ActiveCfg = Debug|x86
{4D0EB624-B2C9-4484-BA73-BFD5653BF0F6}.Debug|x86.Build.0 = Debug|x86
{4D0EB624-B2C9-4484-BA73-BFD5653BF0F6}.Release|x86.ActiveCfg = Release|x86
{4D0EB624-B2C9-4484-BA73-BFD5653BF0F6}.Release|x86.Build.0 = Release|x86
{73C4FAF0-C37A-4CEE-A3F3-B1F80748D5B2}.Debug|x86.ActiveCfg = Debug|Any CPU
{73C4FAF0-C37A-4CEE-A3F3-B1F80748D5B2}.Debug|x86.Build.0 = Debug|Any CPU
{73C4FAF0-C37A-4CEE-A3F3-B1F80748D5B2}.Release|x86.ActiveCfg = Release|Any CPU
{73C4FAF0-C37A-4CEE-A3F3-B1F80748D5B2}.Release|x86.Build.0 = Release|Any CPU
{076A871B-0C13-47D8-8923-B9242995BFF8}.Debug|x86.ActiveCfg = Debug|x86
{076A871B-0C13-47D8-8923-B9242995BFF8}.Debug|x86.Build.0 = Debug|x86
{076A871B-0C13-47D8-8923-B9242995BFF8}.Release|x86.ActiveCfg = Release|x86
{076A871B-0C13-47D8-8923-B9242995BFF8}.Release|x86.Build.0 = Release|x86
{33D1E7E3-A123-43F0-B047-163C6E75D3BF}.Debug|x86.ActiveCfg = Debug|x86
{33D1E7E3-A123-43F0-B047-163C6E75D3BF}.Debug|x86.Build.0 = Debug|x86
{33D1E7E3-A123-43F0-B047-163C6E75D3BF}.Release|x86.ActiveCfg = Release|x86
{33D1E7E3-A123-43F0-B047-163C6E75D3BF}.Release|x86.Build.0 = Release|x86
{0D7BFE1A-730A-48B0-A99A-F6E6A6C134DC}.Debug|x86.ActiveCfg = Debug|x86
{0D7BFE1A-730A-48B0-A99A-F6E6A6C134DC}.Debug|x86.Build.0 = Debug|x86
{0D7BFE1A-730A-48B0-A99A-F6E6A6C134DC}.Release|x86.ActiveCfg = Release|x86
{0D7BFE1A-730A-48B0-A99A-F6E6A6C134DC}.Release|x86.Build.0 = Release|x86
{73636472-C245-4F57-9229-1DB22D643DFD}.Debug|x86.ActiveCfg = Debug|x86
{73636472-C245-4F57-9229-1DB22D643DFD}.Debug|x86.Build.0 = Debug|x86
{73636472-C245-4F57-9229-1DB22D643DFD}.Release|x86.ActiveCfg = Release|x86
{73636472-C245-4F57-9229-1DB22D643DFD}.Release|x86.Build.0 = Release|x86
{8846BDE1-3377-4BED-BAB4-820F5CDF6D37}.Debug|x86.ActiveCfg = Debug|x86
{8846BDE1-3377-4BED-BAB4-820F5CDF6D37}.Debug|x86.Build.0 = Debug|x86
{8846BDE1-3377-4BED-BAB4-820F5CDF6D37}.Release|x86.ActiveCfg = Release|x86
{8846BDE1-3377-4BED-BAB4-820F5CDF6D37}.Release|x86.Build.0 = Release|x86
{1A66B3FB-3482-4981-B3E9-2658A8773E9A}.Debug|x86.ActiveCfg = Debug|x86
{1A66B3FB-3482-4981-B3E9-2658A8773E9A}.Debug|x86.Build.0 = Debug|x86
{1A66B3FB-3482-4981-B3E9-2658A8773E9A}.Release|x86.ActiveCfg = Release|x86
{1A66B3FB-3482-4981-B3E9-2658A8773E9A}.Release|x86.Build.0 = Release|x86
{C5EBF917-C812-4D46-B7EE-0960FEB51081}.Debug|x86.ActiveCfg = Debug|x86
{C5EBF917-C812-4D46-B7EE-0960FEB51081}.Debug|x86.Build.0 = Debug|x86
{C5EBF917-C812-4D46-B7EE-0960FEB51081}.Release|x86.ActiveCfg = Release|x86
{C5EBF917-C812-4D46-B7EE-0960FEB51081}.Release|x86.Build.0 = Release|x86
{E46AB94E-5081-B7E4-99F8-4206054E886C}.Debug|x86.ActiveCfg = Debug|x86
{E46AB94E-5081-B7E4-99F8-4206054E886C}.Debug|x86.Build.0 = Debug|x86
{E46AB94E-5081-B7E4-99F8-4206054E886C}.Release|x86.ActiveCfg = Release|x86
{E46AB94E-5081-B7E4-99F8-4206054E886C}.Release|x86.Build.0 = Release|x86
{C166803B-011F-4EAF-B8C2-D7DBBA3CF1EC}.Debug|x86.ActiveCfg = Debug|x86
{C166803B-011F-4EAF-B8C2-D7DBBA3CF1EC}.Debug|x86.Build.0 = Debug|x86
{C166803B-011F-4EAF-B8C2-D7DBBA3CF1EC}.Release|x86.ActiveCfg = Release|x86
{C166803B-011F-4EAF-B8C2-D7DBBA3CF1EC}.Release|x86.Build.0 = Release|x86
{10E2D025-DED3-490D-8EC6-E99B30FE3E4F}.Debug|x86.ActiveCfg = Debug|Any CPU
{10E2D025-DED3-490D-8EC6-E99B30FE3E4F}.Debug|x86.Build.0 = Debug|Any CPU
{10E2D025-DED3-490D-8EC6-E99B30FE3E4F}.Release|x86.ActiveCfg = Release|Any CPU
{10E2D025-DED3-490D-8EC6-E99B30FE3E4F}.Release|x86.Build.0 = Release|Any CPU
{558BCEC3-1B1F-4DEC-AF4C-47B404A05DE6}.Debug|x86.ActiveCfg = Debug|Any CPU
{558BCEC3-1B1F-4DEC-AF4C-47B404A05DE6}.Debug|x86.Build.0 = Debug|Any CPU
{558BCEC3-1B1F-4DEC-AF4C-47B404A05DE6}.Release|x86.ActiveCfg = Release|Any CPU
{558BCEC3-1B1F-4DEC-AF4C-47B404A05DE6}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{C75D4267-5757-4078-BCF4-7136BE033E96} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{D56A7E3F-FF5C-4EC2-879F-1260ABBD1903} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{43B5C8AC-74C4-4EB4-AF2D-C62E36F41379} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{10E2D025-DED3-490D-8EC6-E99B30FE3E4F} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{8B817EDA-6575-4C17-8255-85652BDD1366} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{83A10A50-EF0D-C64A-B801-5EA8242DE8B2} = {7B2816C2-7370-43B2-820E-FC9C798429BB}
{95A93EAD-0135-AC71-0A46-2F6676500872} = {7B2816C2-7370-43B2-820E-FC9C798429BB}
@ -177,15 +182,17 @@ Global
{70148081-5C0E-A9D3-457B-3FE431140F40} = {7B2816C2-7370-43B2-820E-FC9C798429BB}
{C105FD61-2D91-6A26-36A2-ED1AA2ACC626} = {7B2816C2-7370-43B2-820E-FC9C798429BB}
{189FF169-0498-10BC-2DCA-F5401922F0C7} = {7B2816C2-7370-43B2-820E-FC9C798429BB}
{558BCEC3-1B1F-4DEC-AF4C-47B404A05DE6} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{39EC3FCA-104C-48DA-8B08-18A11148B8F7} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{DEAAD0EA-0FC2-427A-8B7A-173872FD3629} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{44509EA7-2580-46DE-9557-6AA3B64C1F6B} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{7222DF15-4E26-417D-8B5A-5BD9F1006219} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{5E0CB07E-E4DF-4590-9FF4-C78A92A2D230} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{3B06BDD0-46A5-4362-85BE-3EB7C438D58C} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{22434C3A-ED76-4769-A384-5F48ED66EE75} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{76C06121-9565-438F-A750-024641D9CDF2} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{B46AC5CA-D13A-4F82-8A83-76B32F2F74EF} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{73C4FAF0-C37A-4CEE-A3F3-B1F80748D5B2} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{076A871B-0C13-47D8-8923-B9242995BFF8} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{33D1E7E3-A123-43F0-B047-163C6E75D3BF} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{0D7BFE1A-730A-48B0-A99A-F6E6A6C134DC} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{73636472-C245-4F57-9229-1DB22D643DFD} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{8846BDE1-3377-4BED-BAB4-820F5CDF6D37} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{1A66B3FB-3482-4981-B3E9-2658A8773E9A} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{C5EBF917-C812-4D46-B7EE-0960FEB51081} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{10E2D025-DED3-490D-8EC6-E99B30FE3E4F} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{558BCEC3-1B1F-4DEC-AF4C-47B404A05DE6} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
EndGlobalSection
EndGlobal

Просмотреть файл

@ -47,6 +47,9 @@ namespace Embeddinator
string binPath = MonoDroidSdk.BinPath;
if (binPath == null)
throw new Exception ($"Cannot find Android SDK installed.");
//On Windows, it is generally correct, but probe for "lib"
if (File.Exists(Combine(binPath, "lib")))
return GetFullPath(MonoDroidSdk.BinPath);

Просмотреть файл

@ -218,6 +218,11 @@ Selectors on the [NSObjectProtocol](https://developer.apple.com/reference/object
Note: The list of reserved selectors will evolve with new versions of the tool.
<h3><a name="EM1052"/>Element `E` is not generated its name conflicts with other elements on the same class.</h3>
This is a **warning** that Element `E` is not generated as its name conflicts with other elements on the same class.
<!-- 2xxx: code generation -->
# EM2xxx: Code Generation

Просмотреть файл

@ -41,3 +41,4 @@ Known Issues
A list of issues, including bugs, enhancements and ideas, is being tracked on [github](https://github.com/mono/Embeddinator-4000/issues).

30
objcgen/CachedValue.cs Normal file
Просмотреть файл

@ -0,0 +1,30 @@
using System;
namespace Embeddinator
{
class CachedValue<T> where T : class
{
Func<T> CalculateProc;
T LastCalculatedValue;
public bool IsFrozen { get; private set; }
public void Freeze () => IsFrozen = true;
public CachedValue (Func<T> calculateProc)
{
CalculateProc = calculateProc;
}
public T Value {
get {
if (IsFrozen) {
if (LastCalculatedValue == null)
LastCalculatedValue = CalculateProc ();
return LastCalculatedValue;
} else {
return CalculateProc ();
}
}
}
}
}

Просмотреть файл

@ -2,7 +2,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using ProductException = Embeddinator.ObjC.EmbeddinatorException;
namespace Embeddinator.ObjC
@ -93,8 +93,10 @@ namespace Embeddinator.ObjC
foreach (var ex in exceptions)
error |= ShowInternal (ex);
if (error)
if (error) {
DumpLog ();
Exit (1);
}
}
static public void Show (Exception e)
@ -107,8 +109,17 @@ namespace Embeddinator.ObjC
foreach (var ex in exceptions)
error |= ShowInternal (ex);
if (error)
if (error) {
DumpLog ();
Exit (1);
}
}
[Conditional ("DEBUG")]
static void DumpLog ()
{
Console.WriteLine ("Debug Log:");
Logger.Dump ();
}
static void Exit (int exitCode)

30
objcgen/Logger.cs Normal file
Просмотреть файл

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
namespace Embeddinator.ObjC
{
public static class Logger
{
public static void Log (string line) => Log (1, line);
#if DEBUG
static List<string> Entries = new List<string> ();
#endif
public static void Log (int verbosityRequired, string line)
{
if (ErrorHelper.Verbosity >= verbosityRequired)
Console.WriteLine (line);
#if DEBUG
Entries.Add (line);
#endif
}
public static void Dump ()
{
#if DEBUG
Entries.ForEach (l => Console.WriteLine (l));
#endif
}
}
}

Просмотреть файл

@ -1,14 +1,14 @@
# Minimum Mono version
MIN_MONO_VERSION=5.0.0.18
MAX_MONO_VERSION=5.2.99
MIN_MONO_URL=https://bosstoragemirror.blob.core.windows.net/wrench/mono-2017-02/9e/9ed0907eea13005d4e93b9c5f42c5c3015eba409/MonoFramework-MDK-5.0.0.18.macos10.xamarin.universal.pkg
MIN_MONO_VERSION=5.4.1.7
MAX_MONO_VERSION=5.4.1.7
MIN_MONO_URL=https://download.mono-project.com/archive/5.4.1/macos-10-universal/MonoFramework-MDK-5.4.1.7.macos10.xamarin.universal.pkg
# Minimum Xamarin.iOS version
MIN_XI_VERSION=10.11.0.136
MAX_XI_VERSION=10.11.0.136
MIN_XI_URL=https://bosstoragemirror.blob.core.windows.net/wrench/macios-mac-master/a3/a3264f64d6917ea8a1aab3884e4f51d229f31eda/xamarin.ios-10.11.0.136.pkg
MIN_XI_VERSION=11.6.1.3
MAX_XI_VERSION=11.6.1.3
MIN_XI_URL=https://dl.xamarin.com/MonoTouch/Mac/xamarin.ios-11.6.1.3.pkg
# Minimum Xamarin.Mac version
MIN_XM_VERSION=3.5.0.144
MAX_XM_VERSION=3.5.0.144
MIN_XM_URL=https://bosstoragemirror.blob.core.windows.net/wrench/macios-mac-master/c3/c3cecd577f9d0813308df6d6d7159ed94073ddfb/xamarin.mac-3.5.0.144.pkg
MIN_XM_VERSION=4.0.0.215
MAX_XM_VERSION=4.0.0.215
MIN_XM_URL=https://dl.xamarin.com/XamarinforMac/Mac/xamarin.mac-4.0.0.215.pkg

Просмотреть файл

@ -2,7 +2,7 @@ all: bin/Debug/objcgen.exe shellcheck
-include Make.config.inc
PACKAGE_VERSION=0.2.0
PACKAGE_VERSION=0.3.0
PACKAGE_FULLVERSION=$(PACKAGE_VERSION).$(COMMIT_DISTANCE)
Make.config.inc: Makefile

Просмотреть файл

@ -61,10 +61,12 @@ namespace Embeddinator.ObjC {
{
if (t.IsByRef) {
var et = t.GetElementType ();
if (Type.GetTypeCode (et) == TypeCode.Decimal) // This is boxed into NSDecimalNumber
var typecode = Type.GetTypeCode (et);
if (typecode == TypeCode.Decimal || typecode == TypeCode.DateTime) // This is boxed into NSDecimalNumber/NSDate
return GetTypeName (et) + "_Nonnull * _Nullable";
return GetTypeName (et) + (et.IsValueType ? " " : " _Nonnull ") + "* _Nullable";
return GetTypeName (et) + " * " + (et.IsValueType ? "_Nullable" : "_Nonnull");
}
if (t.IsEnum)
@ -117,6 +119,8 @@ namespace Embeddinator.ObjC {
return "NSString *";
case TypeCode.Decimal:
return "NSDecimalNumber *";
case TypeCode.DateTime:
return "NSDate *";
default:
throw new NotImplementedException ($"Converting type {t.Name} to a native type name");
}
@ -174,6 +178,8 @@ namespace Embeddinator.ObjC {
return "string";
case TypeCode.Decimal:
return "System.Decimal";
case TypeCode.DateTime:
return "System.DateTime";
default:
throw new NotImplementedException ($"Converting type {t.Name} to a mono type name");
}
@ -205,6 +211,8 @@ namespace Embeddinator.ObjC {
return $"NSArray<{GetObjCName (t)} *> *";
case TypeCode.Decimal:
return "NSArray <NSDecimalNumber *> *";
case TypeCode.DateTime:
return "NSArray <NSDate *> *";
default:
throw new NotImplementedException ($"Converting type {t.Name} to a native type name");
}
@ -225,6 +233,8 @@ namespace Embeddinator.ObjC {
{
string pName = p.Name;
string ptname = GetTypeName (p.ParameterType);
if (RestrictedNames.IsRestrictedName (pName))
pName = "managed" + pName;
if (p.Name.Length < 3) {
if (!ObjCTypeToArgument.TryGetValue (ptname, out pName))
pName = "anObject";

76
objcgen/TypeMapper.cs Normal file
Просмотреть файл

@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
namespace Embeddinator.ObjC
{
public enum DuplicationStatus
{
None,
Unresolvable
}
public class TypeMapper
{
Dictionary<ProcessedType, Dictionary<string, ProcessedMemberBase>> MappedTypes = new Dictionary<ProcessedType, Dictionary<string, ProcessedMemberBase>> ();
Dictionary <string, ProcessedMemberBase> GetRegistrationForType (ProcessedType t)
{
Dictionary<string, ProcessedMemberBase> data;
if (MappedTypes.TryGetValue (t, out data))
return data;
return null;
}
public bool IsSelectorTaken (ProcessedMemberBase member)
{
var typeRegistration = GetRegistrationForType (member.DeclaringType);
if (typeRegistration != null) {
foreach (var selector in member.Selectors) {
if (typeRegistration.ContainsKey (selector))
return true;
}
}
return false;
}
public IEnumerable <ProcessedMemberBase> WithSameSelector (ProcessedMemberBase member)
{
var typeRegistration = GetRegistrationForType (member.DeclaringType);
if (typeRegistration != null) {
foreach (var selector in member.Selectors) {
ProcessedMemberBase registeredMember = null;
if (typeRegistration.TryGetValue (selector, out registeredMember))
yield return registeredMember;
}
}
}
public void Register (ProcessedMemberBase member)
{
Logger.Log ($"TypeMapper Register: {member} {String.Join (" ", member.Selectors)}");
var typeRegistration = GetRegistrationForType (member.DeclaringType);
if (typeRegistration == null) {
typeRegistration = new Dictionary<string, ProcessedMemberBase> ();
MappedTypes.Add (member.DeclaringType, typeRegistration);
}
foreach (var selector in member.Selectors) {
typeRegistration.Add (selector, member);
}
}
public DuplicationStatus CheckForDuplicateSelectors (ProcessedMemberBase member)
{
if (IsSelectorTaken (member)) {
foreach (var conflictMethod in WithSameSelector (member))
conflictMethod.FallBackToTypeName = true;
member.FallBackToTypeName = true;
}
// Check to see if FallBackToTypeName is insufficient and scream
if (IsSelectorTaken (member))
return DuplicationStatus.Unresolvable;
return DuplicationStatus.None;
}
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

947
objcgen/embedder.cs Normal file
Просмотреть файл

@ -0,0 +1,947 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using IKVM.Reflection;
using System.Text;
using System.Xml;
namespace Embeddinator.ObjC
{
public class Embedder
{
string outputDirectory = ".";
public string OutputDirectory
{
get { return outputDirectory; }
set
{
if (!Directory.Exists (value)) {
try {
Directory.CreateDirectory (value);
Console.WriteLine ($"Creating output directory `{Path.GetFullPath (value)}`");
}
catch (Exception e) {
throw new EmbeddinatorException (1, true, e, $"Could not create output directory `{value}`");
}
}
outputDirectory = value;
}
}
string bundleIdentifier;
public string BundleIdentifier
{
get { return bundleIdentifier ?? LibraryName; }
set { bundleIdentifier = value; }
}
public bool CompileCode { get; set; }
public bool Debug { get; set; }
public bool Extension { get; set; }
public bool Shared { get { return CompilationTarget == CompilationTarget.SharedLibrary; } }
public bool EnableLinker { get; set; }
public string LibraryName { get; set; }
public List<string> ABIs { get; private set; } = new List<string> ();
public void SetPlatform (string platform)
{
switch (platform.ToLowerInvariant ()) {
case "osx":
case "macosx":
case "macos":
case "mac":
Platform = Platform.macOS;
EnableLinker = false;
break;
case "macosmodern":
case "macos-modern":
Platform = Platform.macOSModern;
EnableLinker = true;
break;
case "macosfull":
case "macos-full":
Platform = Platform.macOSFull;
EnableLinker = false;
break;
case "macossystem":
case "macos-system":
Platform = Platform.macOSSystem;
EnableLinker = false;
break;
case "ios":
Platform = Platform.iOS;
EnableLinker = true;
break;
case "tvos":
Platform = Platform.tvOS;
EnableLinker = true;
break;
case "watchos":
Platform = Platform.watchOS;
EnableLinker = true;
break;
default:
throw new EmbeddinatorException (3, true, $"The platform `{platform}` is not valid.");
}
}
public void SetTarget (string value)
{
switch (value.ToLowerInvariant ()) {
case "objc":
case "obj-c":
case "objectivec":
case "objective-c":
TargetLanguage = TargetLanguage.ObjectiveC;
break;
default:
throw new EmbeddinatorException (4, true, $"The target `{value}` is not valid.");
}
}
public void SetCompilationTarget (string value)
{
switch (value.ToLowerInvariant ()) {
case "library":
case "sharedlibrary":
case "dylib":
CompilationTarget = CompilationTarget.SharedLibrary;
break;
case "framework":
CompilationTarget = CompilationTarget.Framework;
break;
case "static":
case "staticlibrary":
CompilationTarget = CompilationTarget.StaticLibrary;
break;
default:
throw new EmbeddinatorException (5, true, $"The compilation target `{value}` is not valid.");
}
}
public List<Assembly> Assemblies { get; private set; } = new List<Assembly> ();
public Platform Platform { get; set; } = Platform.macOS;
public TargetLanguage TargetLanguage { get; private set; } = TargetLanguage.ObjectiveC;
public CompilationTarget CompilationTarget { get; set; } = CompilationTarget.SharedLibrary;
public string [] PlatformSdkDirectories
{
get
{
switch (Platform) {
case Platform.iOS:
return new[] { "/Library/Frameworks/Xamarin.iOS.framework/Versions/Current/lib/mono/Xamarin.iOS" };
case Platform.tvOS:
return new[] { "/Library/Frameworks/Xamarin.iOS.framework/Versions/Current/lib/mono/Xamarin.TVOS" };
case Platform.watchOS:
return new[] { "/Library/Frameworks/Xamarin.iOS.framework/Versions/Current/lib/mono/Xamarin.WatchOS" };
case Platform.macOS:
case Platform.macOSSystem:
return new[] { "/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/4.5", "/Library/Frameworks/Xamarin.Mac.framework/Versions/Current/lib/mono/4.5" };
case Platform.macOSFull:
return new[] { "/Library/Frameworks/Xamarin.Mac.framework/Versions/Current/lib/mono/4.5" };
case Platform.macOSModern:
return new[] { "/Library/Frameworks/Xamarin.Mac.framework/Versions/Current/lib/mono/Xamarin.Mac" };
default:
throw ErrorHelper.CreateError (99, "Internal error: invalid platform {0}. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues).", Platform);
}
}
}
public int Generate (List<string> args)
{
Console.WriteLine ("Parsing assemblies...");
var universe = new Universe (UniverseOptions.MetadataOnly);
universe.AssemblyResolve += (object sender, IKVM.Reflection.ResolveEventArgs resolve_args) => {
var directories = new List<string> ();
foreach (var v in PlatformSdkDirectories) {
directories.Add (v);
directories.Add (Path.Combine (v, "Facades"));
}
foreach (var asm in Assemblies)
directories.Add (Path.GetDirectoryName (asm.Location));
AssemblyName an = new AssemblyName (resolve_args.Name);
foreach (var dir in directories) {
var filename = Path.Combine (dir, an.Name + ".dll");
if (File.Exists (filename))
return universe.LoadFile (filename);
}
throw ErrorHelper.CreateError (13, $"Can't find the assembly '{resolve_args.Name}', referenced by '{resolve_args.RequestingAssembly.FullName}'.");
};
foreach (var arg in args) {
if (!File.Exists (arg))
throw ErrorHelper.CreateError (11, $"The assembly {arg} does not exist.");
Assemblies.Add (universe.LoadFile (arg));
Console.WriteLine ($"\tParsed '{arg}'");
}
// if not specified then we use the first specified assembly name
if (LibraryName == null)
LibraryName = Path.GetFileNameWithoutExtension (args[0]);
Console.WriteLine ("Processing assemblies...");
var p = new ObjCProcessor ();
p.Process (Assemblies.Select (x => new ProcessedAssembly (x) { UserCode = true}));
Console.WriteLine ("Generating binding code...");
var g = new ObjCGenerator () {
Processor = p,
GenerateLinkerExclusions = EnableLinker,
};
g.Generate ();
g.Write (OutputDirectory);
var exe = typeof (Driver).Assembly;
foreach (var res in exe.GetManifestResourceNames ()) {
if (res == "main.c") {
// no main is needed for dylib and don't re-write an existing main.c file - it's a template
if (CompilationTarget != CompilationTarget.StaticLibrary || File.Exists ("main.c"))
continue;
}
var path = Path.Combine (OutputDirectory, res);
Console.WriteLine ($"\tGenerated: {path}");
using (var sw = new StreamWriter (path))
exe.GetManifestResourceStream (res).CopyTo (sw.BaseStream);
}
return 0;
}
static string xcode_app;
public static string XcodeApp
{
get
{
if (string.IsNullOrEmpty (xcode_app)) {
int exitCode;
string output;
if (!Utils.RunProcess ("xcode-select", "-p", out exitCode, out output))
throw ErrorHelper.CreateError (6, "Could not find the Xcode location.");
xcode_app = Path.GetDirectoryName (Path.GetDirectoryName (output.Trim ()));
}
return xcode_app;
}
}
class BuildInfo
{
public string Sdk;
public string[] Architectures;
public string SdkName; // used in -m{SdkName}-version-min
public string MinVersion;
public string XamariniOSSDK;
public string CompilerFlags;
public string LinkerFlags;
public bool IsSimulator
{
get { return Sdk.Contains ("Simulator"); }
}
}
void VerifyDependencies ()
{
SystemCheck.VerifyMono ();
switch (Platform) {
case Platform.iOS:
case Platform.tvOS:
case Platform.watchOS:
SystemCheck.VerifyXamariniOS ();
break;
case Platform.macOS:
case Platform.macOSFull:
case Platform.macOSModern:
case Platform.macOSSystem:
SystemCheck.VerifyXamarinMac ();
break;
default:
throw ErrorHelper.CreateError (99, "Internal error: invalid platform {0}. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues).", Platform);
}
}
public int Compile ()
{
Console.WriteLine ("Compiling binding code...");
VerifyDependencies ();
BuildInfo[] build_infos;
switch (Platform) {
case Platform.macOS:
case Platform.macOSFull:
case Platform.macOSModern:
case Platform.macOSSystem:
build_infos = new BuildInfo[] {
new BuildInfo { Sdk = "MacOSX", Architectures = new string [] { "i386", "x86_64" }, SdkName = "macosx", MinVersion = "10.7" },
};
break;
case Platform.iOS:
build_infos = new BuildInfo[] {
new BuildInfo { Sdk = "iPhoneOS", Architectures = new string [] { "armv7", "armv7s", "arm64" }, SdkName = "iphoneos", MinVersion = "8.0", XamariniOSSDK = "MonoTouch.iphoneos.sdk" },
new BuildInfo { Sdk = "iPhoneSimulator", Architectures = new string [] { "i386", "x86_64" }, SdkName = "ios-simulator", MinVersion = "8.0", XamariniOSSDK = "MonoTouch.iphonesimulator.sdk" },
};
break;
case Platform.tvOS:
build_infos = new BuildInfo[] {
new BuildInfo { Sdk = "AppleTVOS", Architectures = new string [] { "arm64" }, SdkName = "tvos", MinVersion = "9.0", XamariniOSSDK = "Xamarin.AppleTVOS.sdk", CompilerFlags = "-fembed-bitcode", LinkerFlags = "-fembed-bitcode" },
new BuildInfo { Sdk = "AppleTVSimulator", Architectures = new string [] { "x86_64" }, SdkName = "tvos-simulator", MinVersion = "9.0", XamariniOSSDK = "Xamarin.AppleTVSimulator.sdk" },
};
break;
case Platform.watchOS:
build_infos = new BuildInfo[] {
new BuildInfo { Sdk = "WatchOS", Architectures = new string [] { "armv7k" }, SdkName = "watchos", MinVersion = "2.0", XamariniOSSDK = "Xamarin.WatchOS.sdk", CompilerFlags = "-fembed-bitcode", LinkerFlags = "-fembed-bitcode" },
new BuildInfo { Sdk = "WatchSimulator", Architectures = new string [] { "i386" }, SdkName = "watchos-simulator", MinVersion = "2.0", XamariniOSSDK = "Xamarin.WatchSimulator.sdk" },
};
break;
default:
throw ErrorHelper.CreateError (99, "Internal error: invalid platform {0}. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues).", Platform);
}
// filter/validate ABIs
if (ABIs.Count > 0) {
// Validate
var all_architectures = build_infos.SelectMany ((v) => v.Architectures);
var invalid_architectures = ABIs.Except (all_architectures).ToArray ();
if (invalid_architectures.Length > 0) {
var arch = invalid_architectures[0];
throw ErrorHelper.CreateError (8, $"The architecture '{arch}' is not valid for {Platform}. Valid architectures for {Platform} are: {string.Join (", ", all_architectures)}");
}
// Filter
foreach (var info in build_infos)
info.Architectures = info.Architectures.Where ((v) => ABIs.Contains (v)).ToArray ();
}
var lipo_files = new List<string> ();
var output_file = string.Empty;
var files = new string[] {
Path.Combine (OutputDirectory, "glib.c"),
Path.Combine (OutputDirectory, "mono_embeddinator.c"),
Path.Combine (OutputDirectory, "objc-support.m"),
Path.Combine (OutputDirectory, "bindings.m"),
};
switch (CompilationTarget) {
case CompilationTarget.SharedLibrary:
output_file = $"lib{LibraryName}.dylib";
break;
case CompilationTarget.StaticLibrary:
case CompilationTarget.Framework:
output_file = $"{LibraryName}.a";
break;
default:
throw ErrorHelper.CreateError (99, "Internal error: invalid compilation target {0}. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues).", CompilationTarget);
}
int exitCode;
/*
* For static libraries we
* * Compile all source files to .o files, per architecture.
* * Then we archive .o files into per-sdk .a files, then we archive all .o files into a global .a file. So we end up with one .a for device, one for simulator, and one for both device and simulator.
* * Then we dsym the global .a file
*
* For dynamic libraries we
* * Compile all source files to .o files, per architecture.
* * Then we link all .o files per architecture into a .dylib.
* * Then we lipo .dylib files into per-sdk fat .dylib, then we lipo all .dylib into a global .dylib file. So we end up with one fat .dylib for device, one fat .dylib for simulator, and one very fat .dylib for both simulator and device.
* * Finally we dsymutil the global .dylib
*
* For frameworks we
* * First we build the source files to .o files and then archive to .a files just like for static libraries.
* * Then we call mtouch to build a framework of the managed assemblies, passing the static library we just created as a gcc_flag so that it's linked in. This is done per sdk (simulator/device).
* * Finally we merge the simulator framework and the device framework into a global framework, that supports both simulator and device.
* * We dsymutil those frameworks.
*/
foreach (var build_info in build_infos) {
foreach (var arch in build_info.Architectures) {
var archOutputDirectory = Path.Combine (OutputDirectory, arch);
Directory.CreateDirectory (archOutputDirectory);
var common_options = new StringBuilder ("clang ");
if (Debug)
common_options.Append ("-g -O0 ");
else {
common_options.Append ("-O2 ");
if (Platform == Platform.macOS) {
// Token lookup only works if the linker isn't involved.
// If the linker is enabled, all assemblies are loaded and re-saved
// (even if only linking SDK assemblies), which means metadata
// tokens may change even for non-linked assemblies. So completely
// disable token lookup for platforms that uses the linker (all platforms
// except macOS).
common_options.Append ("-DTOKENLOOKUP ");
}
}
common_options.Append ("-fobjc-arc ");
common_options.Append ("-ObjC ");
common_options.Append ("-Wall ");
common_options.Append ($"-arch {arch} ");
common_options.Append ($"-isysroot {XcodeApp}/Contents/Developer/Platforms/{build_info.Sdk}.platform/Developer/SDKs/{build_info.Sdk}.sdk ");
common_options.Append ($"-m{build_info.SdkName}-version-min={build_info.MinVersion} ");
switch (Platform) {
case Platform.macOS:
common_options.Append ("-I/Library/Frameworks/Mono.framework/Versions/Current/include/mono-2.0 ");
break;
case Platform.macOSSystem:
case Platform.macOSModern:
case Platform.macOSFull:
common_options.Append ("-I/Library/Frameworks/Xamarin.Mac.framework/Versions/Current/include ");
common_options.Append ("-DXAMARIN_MAC ");
break;
case Platform.iOS:
case Platform.tvOS:
case Platform.watchOS:
common_options.Append ($"-I/Library/Frameworks/Xamarin.iOS.framework/Versions/Current/SDKs/{build_info.XamariniOSSDK}/usr/include ");
common_options.Append ("-DXAMARIN_IOS ");
break;
default:
throw ErrorHelper.CreateError (99, "Internal error: invalid platform {0}. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues).", Platform);
}
// Build each source file to a .o
var object_files = new List<string> ();
foreach (var file in files) {
var compiler_options = new StringBuilder (common_options.ToString ());
compiler_options.Append ("-DMONO_EMBEDDINATOR_DLL_EXPORT ");
compiler_options.Append (build_info.CompilerFlags).Append (" ");
compiler_options.Append ("-c ");
compiler_options.Append (Utils.Quote (file)).Append (" ");
var objfile = Path.Combine (archOutputDirectory, Path.ChangeExtension (Path.GetFileName (file), "o"));
compiler_options.Append ($"-o {Utils.Quote (objfile)} ");
object_files.Add (objfile);
if (!Utils.Xcrun (compiler_options, out exitCode))
return exitCode;
}
// Link/archive object files to .a/.dylib
switch (CompilationTarget) {
case CompilationTarget.SharedLibrary:
// Link all the .o files into a .dylib
var options = new StringBuilder (common_options.ToString ());
options.Append ($"-dynamiclib ");
options.Append (build_info.LinkerFlags).Append (" ");
options.Append ("-lobjc ");
options.Append ("-framework CoreFoundation ");
options.Append ("-framework Foundation ");
options.Append ($"-install_name {Utils.Quote ("@rpath/" + output_file)} ");
foreach (var objfile in object_files)
options.Append (Utils.Quote (objfile)).Append (" ");
var dynamic_ofile = Path.Combine (archOutputDirectory, output_file);
options.Append ($"-o ").Append (Utils.Quote (dynamic_ofile)).Append (" ");
lipo_files.Add (dynamic_ofile);
if (!string.IsNullOrEmpty (build_info.XamariniOSSDK)) {
options.Append ($"-L/Library/Frameworks/Xamarin.iOS.framework/Versions/Current/SDKs/{build_info.XamariniOSSDK}/usr/lib ");
options.Append ("-lxamarin ");
}
else {
options.Append ("-L/Library/Frameworks/Mono.framework/Versions/Current/lib/ ");
}
options.Append ("-lmonosgen-2.0 ");
if (!Utils.Xcrun (options, out exitCode))
return exitCode;
break;
case CompilationTarget.Framework:
case CompilationTarget.StaticLibrary:
// Archive all the .o files into a .a
var archive_options = new StringBuilder ("ar cru ");
var static_ofile = Path.Combine (archOutputDirectory, output_file);
archive_options.Append (static_ofile).Append (" ");
lipo_files.Add (static_ofile);
foreach (var objfile in object_files)
archive_options.Append (objfile).Append (" ");
if (!Utils.Xcrun (archive_options, out exitCode))
return exitCode;
break;
default:
throw ErrorHelper.CreateError (99, "Internal error: invalid compilation target {0}. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues).", CompilationTarget);
}
}
// Create the per-sdk output file
var sdk_output_file = Path.Combine (OutputDirectory, build_info.Sdk, output_file);
if (!Utils.Lipo (lipo_files, sdk_output_file, out exitCode))
return exitCode;
if (CompilationTarget == CompilationTarget.Framework) {
var appdir = Path.GetFullPath (Path.Combine (OutputDirectory, build_info.Sdk, LibraryName));
var cachedir = Path.GetFullPath (Path.Combine (outputDirectory, build_info.Sdk, "build-cache"));
string fwdir;
string headers;
switch (Platform) {
case Platform.macOS:
case Platform.macOSFull:
case Platform.macOSModern:
case Platform.macOSSystem:
fwdir = Path.Combine (appdir, $"{LibraryName}.framework");
headers = Path.Combine (fwdir, "Headers");
Directory.CreateDirectory (Path.Combine (fwdir, "Versions", "A", "Headers"));
Utils.CreateSymlink (Path.Combine (fwdir, "Versions", "Current"), "A");
Utils.CreateSymlink (Path.Combine (fwdir, "Headers"), "Versions/Current/Headers");
Utils.CreateSymlink (Path.Combine (fwdir, "Resources"), "Versions/Current/Resources");
break;
case Platform.iOS:
case Platform.tvOS:
case Platform.watchOS:
fwdir = Path.Combine (appdir, "Frameworks", $"{LibraryName}.framework");
headers = Path.Combine (fwdir, "Headers");
Directory.CreateDirectory (headers);
break;
default:
throw ErrorHelper.CreateError (99, "Internal error: invalid platform {0}. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues).", Platform);
}
switch (Platform) {
case Platform.macOS:
var resources_dir = Path.Combine (fwdir, "Versions", "A", "Resources");
Directory.CreateDirectory (resources_dir);
// Link the .a files into a framework
var options = new StringBuilder ("clang ");
options.Append ($"-dynamiclib ");
options.Append (build_info.LinkerFlags).Append (" ");
options.Append ("-lobjc ");
options.Append ("-framework CoreFoundation ");
options.Append ("-framework Foundation ");
options.Append ($"-install_name {Utils.Quote ($"@loader_path/../Frameworks/{LibraryName}.framework/Versions/A/{LibraryName}")} ");
options.Append ("-force_load ").Append (Utils.Quote (sdk_output_file)).Append (" ");
options.Append ($"-o ").Append (Utils.Quote (Path.Combine (fwdir, "Versions", "A", LibraryName))).Append (" ");
options.Append ("-L/Library/Frameworks/Mono.framework/Versions/Current/lib/ ");
options.Append ("-lmonosgen-2.0 ");
if (!Utils.Xcrun (options, out exitCode))
return exitCode;
// Create framework structure
Utils.CreateSymlink (Path.Combine (fwdir, LibraryName), $"Versions/Current/{LibraryName}");
File.WriteAllText (Path.Combine (fwdir, "Versions", "A", "Resources", "Info.plist"), $@"<?xml version=""1.0"" encoding=""UTF-8""?>
<!DOCTYPE plist PUBLIC ""-//Apple//DTD PLIST 1.0//EN"" ""http://www.apple.com/DTDs/PropertyList-1.0.dtd"">
<plist version=""1.0"">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>{LibraryName}</string>
<key>CFBundleIdentifier</key>
<string>{BundleIdentifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>{LibraryName}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>CFBundleVersion</key>
<string>1</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>8C38</string>
<key>DTPlatformVersion</key>
<string>GM</string>
<key>DTSDKBuild</key>
<string>16C58</string>
<key>DTSDKName</key>
<string>macosx10.12</string>
<key>DTXcode</key>
<string>0620</string>
<key>DTXcodeBuild</key>
<string>6C131e</string>
<key>BuildMachineOSBuild</key>
<string>13F34</string>
</dict>
</plist>
");
// Copy any assemblies to the framework
var bundleDir = Path.Combine (resources_dir, "MonoBundle");
Directory.CreateDirectory (bundleDir);
foreach (var asm in Assemblies) {
var src = asm.Location;
var tgt = Path.Combine (bundleDir, Path.GetFileName (asm.Location));
File.Copy (src, tgt, true);
Utils.FileCopyIfExists (Path.ChangeExtension (src, "pdb"), Path.ChangeExtension (tgt, "pdb"));
Utils.FileCopyIfExists (src + ".config", tgt + ".config");
// FIXME: Satellite assemblies?
}
// Add the headers to the framework
File.Copy (Path.Combine (OutputDirectory, "embeddinator.h"), Path.Combine (headers, "embeddinator.h"), true);
File.Copy (Path.Combine (OutputDirectory, "bindings.h"), Path.Combine (headers, $"bindings.h"), true);
// Create an umbrella header for the everything in the framework.
File.WriteAllText (Path.Combine (headers, LibraryName + ".h"),
@"
#include ""bindings.h""
");
break;
case Platform.macOSFull:
case Platform.macOSModern:
case Platform.macOSSystem:
var mmp = new StringBuilder ();
mmp.Append ($"--output={Utils.Quote (appdir)} ");
mmp.Append ($"--arch={string.Join (",", build_info.Architectures)} ");
if (build_info.Architectures.Length > 1)
throw new NotImplementedException ("fat Xamarin.Mac apps");
mmp.Append ($"--sdkroot {XcodeApp} ");
mmp.Append ($"--minos {build_info.MinVersion} ");
mmp.Append ($"--embeddinator ");
foreach (var asm in Assemblies)
mmp.Append (Utils.Quote (Path.GetFullPath (asm.Location))).Append (" ");
mmp.Append ($"-a:{GetPlatformAssembly ()} ");
mmp.Append ($"--sdk {GetSdkVersion (build_info.Sdk.ToLower ())} ");
// FIXME: once merged add support for linking the platform (Xamarin.Mac.dll)
if (Platform == Platform.macOSModern) {
mmp.Append ("--linksdkonly ");
mmp.Append ($"--xml={Utils.Quote (Path.Combine (OutputDirectory, "bindings.xml"))} ");
}
else {
// mmp default is to link everything
mmp.Append ("--nolink ");
}
mmp.Append ("--registrar:static ");
mmp.Append ($"--cache {Utils.Quote (cachedir)} ");
if (Debug)
mmp.Append ("--debug ");
mmp.Append ("-p "); // generate a plist
mmp.Append ($"--target-framework {GetTargetFramework ()} ");
mmp.Append ($"\"--link_flags=-force_load {Path.GetFullPath (sdk_output_file)}\" ");
if (!Utils.RunProcess ("/Library/Frameworks/Xamarin.Mac.framework/Versions/Current/bin/mmp", mmp.ToString (), out exitCode))
return exitCode;
// Add the headers to the framework
File.Copy (Path.Combine (OutputDirectory, "embeddinator.h"), Path.Combine (headers, "embeddinator.h"), true);
File.Copy (Path.Combine (OutputDirectory, "bindings.h"), Path.Combine (headers, $"bindings.h"), true);
// Create an umbrella header for the everything in the framework.
File.WriteAllText (Path.Combine (headers, LibraryName + ".h"),
@"
#include ""bindings.h""
#if defined(__i386__)
#include ""registrar-i386.h""
#elif defined(__x86_64__)
#include ""registrar-x86_64.h""
#else
#error Unknown architecture
#endif
");
if (build_info.Architectures.Contains ("i386"))
Utils.FileCopyIfExists (Path.Combine (cachedir, "registrar.h"), Path.Combine (headers, "registrar-i386.h"));
if (build_info.Architectures.Contains ("x86_64"))
Utils.FileCopyIfExists (Path.Combine (cachedir, "registrar.h"), Path.Combine (headers, "registrar-x86_64.h"));
break;
case Platform.iOS:
case Platform.tvOS:
case Platform.watchOS:
var mtouch = new StringBuilder ();
mtouch.Append (build_info.IsSimulator ? "--sim " : "--dev ");
mtouch.Append ($"{Utils.Quote (appdir)} ");
mtouch.Append ($"--abi={string.Join (",", build_info.Architectures)} ");
mtouch.Append ($"--sdkroot {XcodeApp} ");
mtouch.Append ($"--targetver {build_info.MinVersion} ");
mtouch.Append ("--dsym:false ");
mtouch.Append ("--msym:false ");
mtouch.Append ($"--embeddinator ");
foreach (var asm in Assemblies)
mtouch.Append (Utils.Quote (Path.GetFullPath (asm.Location))).Append (" ");
mtouch.Append ($"-r:{GetPlatformAssembly ()} ");
mtouch.Append ($"--sdk {GetSdkVersion (build_info.Sdk.ToLower ())} ");
mtouch.Append ("--linksdkonly ");
mtouch.Append ($"--xml={Utils.Quote (Path.Combine (OutputDirectory, "bindings.xml"))} ");
mtouch.Append ("--registrar:static ");
mtouch.Append ($"--cache {Utils.Quote (cachedir)} ");
if (Debug)
mtouch.Append ("--debug ");
mtouch.Append ($"--assembly-build-target=@all=framework={LibraryName}.framework ");
mtouch.Append ($"--target-framework {GetTargetFramework ()} ");
mtouch.Append ($"\"--gcc_flags=-force_load {Path.GetFullPath (sdk_output_file)}\" ");
if (!Utils.RunProcess ("/Library/Frameworks/Xamarin.iOS.framework/Versions/Current/bin/mtouch", mtouch.ToString (), out exitCode))
return exitCode;
// Add the headers to the framework
File.Copy (Path.Combine (OutputDirectory, "embeddinator.h"), Path.Combine (headers, "embeddinator.h"), true);
File.Copy (Path.Combine (OutputDirectory, "bindings.h"), Path.Combine (headers, $"bindings.h"), true);
// Create an umbrella header for the everything in the framework.
File.WriteAllText (Path.Combine (headers, LibraryName + ".h"),
@"
#include ""bindings.h""
#if defined(__i386__)
#include ""registrar-i386.h""
#elif defined(__x86_64__)
#include ""registrar-x86_64.h""
#elif defined(__arm__)
#include ""registrar-arm32.h"" // this includes all 32-bit arm architectures.
#elif defined(__aarch64__)
#include ""registrar-arm64.h""
#else
#error Unknown architecture
#endif
");
switch (Platform) {
case Platform.iOS:
if (build_info.IsSimulator) {
Utils.FileCopyIfExists (Path.Combine (cachedir, "32", "registrar.h"), Path.Combine (headers, "registrar-i386.h"));
Utils.FileCopyIfExists (Path.Combine (cachedir, "64", "registrar.h"), Path.Combine (headers, "registrar-x86_64.h"));
}
else {
Utils.FileCopyIfExists (Path.Combine (cachedir, "32", "registrar.h"), Path.Combine (headers, "registrar-arm32.h"));
Utils.FileCopyIfExists (Path.Combine (cachedir, "64", "registrar.h"), Path.Combine (headers, "registrar-arm64.h"));
}
break;
case Platform.tvOS:
Utils.FileCopyIfExists (Path.Combine (cachedir, "registrar.h"), Path.Combine (headers, build_info.IsSimulator ? "registrar-x86_64.h" : "registrar-arm64.h"));
break;
default:
throw ErrorHelper.CreateError (99, "Internal error: invalid platform {0}. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues).", Platform);
}
break;
default:
throw ErrorHelper.CreateError (99, "Internal error: invalid platform {0}. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues).", Platform);
}
// Move the framework to the output directory
var fwpath = Path.Combine (OutputDirectory, build_info.Sdk, $"{LibraryName}.framework");
if (Directory.Exists (fwpath))
Directory.Delete (fwpath, true);
Directory.Move (fwdir, fwpath);
Directory.Delete (appdir, true); // We don't need this anymore.
}
}
var output_path = Path.Combine (OutputDirectory, output_file);
if (!Utils.Lipo (lipo_files, output_path, out exitCode))
return exitCode;
if (!DSymUtil (output_path, out exitCode))
return exitCode;
if (CompilationTarget == CompilationTarget.Framework) {
var fwpath = Path.Combine (OutputDirectory, $"{LibraryName}.framework");
if (build_infos.Length == 2) {
var dev_fwpath = Path.Combine (OutputDirectory, build_infos[0].Sdk, $"{LibraryName}.framework");
var sim_fwpath = Path.Combine (OutputDirectory, build_infos[1].Sdk, $"{LibraryName}.framework");
if (!MergeFrameworks (fwpath, dev_fwpath, sim_fwpath, out exitCode))
return exitCode;
}
else {
if (Directory.Exists (fwpath))
Directory.Delete (fwpath, true);
var fwsdkpath = Path.Combine (OutputDirectory, build_infos[0].Sdk, $"{LibraryName}.framework");
Directory.Move (fwsdkpath, fwpath);
}
Console.WriteLine ($"Successfully created framework: {fwpath}");
}
else {
Console.WriteLine ($"Successfully created library: {output_path}");
}
return 0;
}
// All files from both frameworks will be included.
// For files present in both frameworks:
// * The executables will be lipoed
// * Info.plist will be manually merged.
// * Headers: should be identical, so we just choose one of them.
// * other files: show an error.
static bool MergeFrameworks (string output, string deviceFramework, string simulatorFramework, out int exitCode)
{
if (deviceFramework[deviceFramework.Length - 1] == Path.DirectorySeparatorChar)
deviceFramework = deviceFramework.Substring (0, deviceFramework.Length - 1);
if (simulatorFramework[simulatorFramework.Length - 1] == Path.DirectorySeparatorChar)
simulatorFramework = simulatorFramework.Substring (0, simulatorFramework.Length - 1);
var name = Path.GetFileNameWithoutExtension (deviceFramework);
var deviceFiles = Directory.GetFiles (deviceFramework, "*", SearchOption.AllDirectories);
var simulatorFiles = Directory.GetFiles (simulatorFramework, "*", SearchOption.AllDirectories);
Directory.CreateDirectory (output);
var executables = new List<string> ();
executables.Add (Path.Combine (deviceFramework, name));
executables.Add (Path.Combine (simulatorFramework, name));
if (!Utils.Lipo (executables, Path.Combine (output, name), out exitCode))
return false;
var relativeDeviceFiles = deviceFiles.Select ((v) => v.Substring (deviceFramework.Length + 1));
var relativeSimulatorFiles = simulatorFiles.Select ((v) => v.Substring (simulatorFramework.Length + 1));
var allFiles = relativeDeviceFiles.Concat (relativeSimulatorFiles).ToList ();
allFiles.RemoveAll ((v) => v == name); // the executable, which we've already handled (lipoed).
var groupedFiles = allFiles.GroupBy ((v) => v);
foreach (var @group in groupedFiles) {
var file = @group.Key;
var unique = @group.Count () == 1;
var targetPath = Path.Combine (output, file);
Directory.CreateDirectory (Path.GetDirectoryName (targetPath));
if (unique) {
// A single file, just copy it.
string srcPath;
if (relativeDeviceFiles.Contains (file)) {
srcPath = Path.Combine (deviceFramework, file);
}
else {
srcPath = Path.Combine (simulatorFramework, file);
}
File.Copy (srcPath, targetPath, true);
}
else {
// Same file in both device and simulator frameworks.
if (file == "Info.plist") {
MergeInfoPlists (Path.Combine (output, file), Path.Combine (deviceFramework, file), Path.Combine (simulatorFramework, file));
}
else if (file.StartsWith ("Headers/", StringComparison.Ordinal)) {
// Headers are identical between simulator and device, so no special processing needed, just choose one of them.
File.Copy (Path.Combine (deviceFramework, file), targetPath, true);
}
else {
throw ErrorHelper.CreateError (10, $"Can't merge the frameworks '{simulatorFramework}' and '{deviceFramework}' because the file '{file}' exists in both.");
}
}
}
return true;
}
// Merge CFBundleSupportPlatforms from both Info.plists.
// At the moment all other values are only from the first plist.
static void MergeInfoPlists (string output, string a, string b)
{
var adoc = new XmlDocument ();
var bdoc = new XmlDocument ();
XmlReaderSettings settings = new XmlReaderSettings () {
XmlResolver = null,
DtdProcessing = DtdProcessing.Parse
};
using (var srA = new StreamReader (a, Encoding.UTF8, true))
using (var readerA = XmlReader.Create (srA, settings))
using (var srB = new StreamReader (b, Encoding.UTF8, true))
using (var readerB = XmlReader.Create (srB, settings)) {
adoc.Load (readerA);
bdoc.Load (readerB);
var a_supported_platforms = ((XmlNode)adoc.SelectSingleNode ("/plist/dict/key[text()='CFBundleSupportedPlatforms']/following-sibling::array"));
var b_supported_platforms = ((XmlNode)bdoc.SelectSingleNode ("/plist/dict/key[text()='CFBundleSupportedPlatforms']/following-sibling::array"));
foreach (XmlNode b_platform in b_supported_platforms.ChildNodes) {
var node = adoc.ImportNode (b_platform, true);
a_supported_platforms.AppendChild (node);
}
var writerSettings = new XmlWriterSettings ();
writerSettings.Encoding = new UTF8Encoding (false);
writerSettings.IndentChars = " ";
writerSettings.Indent = true;
using (var writer = XmlWriter.Create (output, writerSettings))
adoc.Save (writer);
// Apple's plist reader does not like empty internal subset declaration,
// even though this is allowed according to the xml spec: http://stackoverflow.com/a/6192048/183422
// So manually fix the xml :(
var contents = File.ReadAllText (output);
contents = contents.Replace (
@"<!DOCTYPE plist PUBLIC ""-//Apple//DTD PLIST 1.0//EN"" ""http://www.apple.com/DTDs/PropertyList-1.0.dtd""[]>",
@"<!DOCTYPE plist PUBLIC ""-//Apple//DTD PLIST 1.0//EN"" ""http://www.apple.com/DTDs/PropertyList-1.0.dtd"">");
File.WriteAllText (output, contents);
}
}
string GetSdkVersion (string sdk)
{
int exitCode;
string output;
if (!Utils.RunProcess ("xcrun", $"--show-sdk-version --sdk {sdk}", out exitCode, out output))
throw ErrorHelper.CreateError (7, $"Could not get the sdk version for '{sdk}'");
return output.Trim ();
}
string GetPlatformAssembly ()
{
switch (Platform) {
case Platform.macOS:
throw new NotImplementedException ("platform assembly for macOS"); // We need to know full/mobile
case Platform.macOSSystem:
case Platform.macOSFull:
return "/Library/Frameworks/Xamarin.Mac.framework/Versions/Current/lib/mono/4.5/Xamarin.Mac.dll";
case Platform.macOSModern:
return "/Library/Frameworks/Xamarin.Mac.framework/Versions/Current/lib/mono/Xamarin.Mac/Xamarin.Mac.dll";
case Platform.iOS:
return "/Library/Frameworks/Xamarin.iOS.framework/Versions/Current/lib/mono/Xamarin.iOS/Xamarin.iOS.dll";
case Platform.tvOS:
return "/Library/Frameworks/Xamarin.iOS.framework/Versions/Current/lib/mono/Xamarin.TVOS/Xamarin.TVOS.dll";
case Platform.watchOS:
return "/Library/Frameworks/Xamarin.iOS.framework/Versions/Current/lib/mono/Xamarin.WatchOS/Xamarin.WatchOS.dll";
default:
throw ErrorHelper.CreateError (99, "Internal error: invalid platform {0}. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues).", Platform);
}
}
string GetTargetFramework ()
{
switch (Platform) {
case Platform.macOSSystem:
return "Xamarin.Mac,Version=v4.5,Profile=System";
case Platform.macOSFull:
return "Xamarin.Mac,Version=v4.5,Profile=Full";
case Platform.macOSModern:
return "Xamarin.Mac,Version=v2.0,Profile=Mobile";
case Platform.iOS:
return "Xamarin.iOS,v1.0";
case Platform.tvOS:
return "Xamarin.TVOS,v1.0";
case Platform.watchOS:
return "Xamarin.WatchOS,v1.0";
default:
throw ErrorHelper.CreateError (99, "Internal error: invalid platform {0}. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues).", Platform);
}
}
bool DSymUtil (string input, out int exitCode)
{
exitCode = 0;
if (!Debug)
return true;
string output;
switch (CompilationTarget) {
case CompilationTarget.StaticLibrary:
case CompilationTarget.Framework:
return true;
case CompilationTarget.SharedLibrary:
output = input + ".dSYM";
break;
default:
throw ErrorHelper.CreateError (99, "Internal error: invalid compilation target {0}. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues).", CompilationTarget);
}
var dsymutil_options = new StringBuilder ("dsymutil ");
dsymutil_options.Append (Utils.Quote (input)).Append (" ");
dsymutil_options.Append ($"-o {Utils.Quote (output)} ");
return Utils.Xcrun (dsymutil_options, out exitCode);
}
}
}

Просмотреть файл

@ -200,4 +200,12 @@ namespace Embeddinator.ObjC {
return false;
}
}
public static class EnumerableExtensions {
public static IEnumerable<T> Yield<T> (this T item)
{
yield return item;
}
}
}

Просмотреть файл

@ -98,7 +98,7 @@ namespace Embeddinator.ObjC {
var method = "__method";
if (IsVirtual) {
implementation.WriteLine ($"MonoMethod* __virtual_method = mono_object_get_virtual_method ({instance}, __method);");
implementation.WriteLine ($"MonoMethod* __virtual_method = mono_object_get_virtual_method ((MonoObject *){instance}, __method);");
method = "__virtual_method";
}
if (!IsConstructor && (ReturnType != "void"))

Просмотреть файл

@ -60,6 +60,11 @@
<Compile Include="NameGenerator.cs" />
<Compile Include="processor.cs" />
<Compile Include="system-check.cs" />
<Compile Include="embedder.cs" />
<Compile Include="utils.cs" />
<Compile Include="CachedValue.cs" />
<Compile Include="TypeMapper.cs" />
<Compile Include="Logger.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="support\" />

Просмотреть файл

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
@ -10,10 +11,11 @@ namespace Embeddinator.ObjC {
// A set of post-processing steps needed to add hints
// to the input of the generation step
public partial class ObjCProcessor {
TypeMapper Mapper = new TypeMapper ();
protected IEnumerable<ProcessedMethod> PostProcessMethods (IEnumerable<ProcessedMethod> methods)
{
HashSet<string> duplicateNames = FindDuplicateNames (methods);
var equals = new HashSet<MethodInfo> ();
foreach (var m in methods) {
if (m.MethodType == MethodType.NSObjectProcotolIsEqual)
@ -28,19 +30,24 @@ namespace Embeddinator.ObjC {
continue;
}
if (duplicateNames.Contains (CreateStringRep (method)) && method.Name != "CompareTo") // HACK
processedMethod.FallBackToTypeName = true;
if (IsOperatorOrFriendlyVersion (method))
processedMethod.IsOperator = true;
ProcessPotentialNameOverride (processedMethod);
ProcessPotentialName (processedMethod);
if (Mapper.CheckForDuplicateSelectors (processedMethod) == DuplicationStatus.Unresolvable) {
Delayed.Add (ErrorHelper.CreateWarning (1052, $"Element {method.Name} is not generated as its name conflicts with other elements on the same class."));
continue;
}
Mapper.Register (processedMethod);
processedMethod.Freeze ();
yield return processedMethod;
}
}
void ProcessPotentialNameOverride (ProcessedMethod processedMethod)
void ProcessPotentialName (ProcessedMethod processedMethod)
{
MethodInfo method = processedMethod.Method;
if (IsOperatorOrFriendlyVersion (method)) {
@ -48,6 +55,13 @@ namespace Embeddinator.ObjC {
if (nameOverride != null)
processedMethod.NameOverride = nameOverride;
}
string objCSignature = processedMethod.ObjCSignature;
if (RestrictedObjSelectors.IsImportantSelector (objCSignature)) {
string newName = "managed" + method.Name.PascalCase ();
processedMethod.NameOverride = newName;
Delayed.Add (ErrorHelper.CreateWarning (1051, $"Element {method.Name} is generated instead as {newName} because its name conflicts with an important objective-c selector."));
}
}
public bool IsOperatorOrFriendlyVersion (MethodInfo method)
@ -55,84 +69,120 @@ namespace Embeddinator.ObjC {
return method.IsOperatorMethod () || OperatorOverloads.MatchesOperatorFriendlyName (method);
}
protected IEnumerable<ProcessedProperty> PostProcessProperties (IEnumerable<PropertyInfo> properties)
protected IEnumerable<ProcessedProperty> PostProcessProperties (IEnumerable<ProcessedProperty> properties)
{
foreach (PropertyInfo property in properties) {
ProcessedProperty processedProperty = new ProcessedProperty (property, this);
foreach (ProcessedProperty processedProperty in properties) {
ProcessPotentialName (processedProperty);
if (Mapper.CheckForDuplicateSelectors (processedProperty) == DuplicationStatus.Unresolvable){
Delayed.Add (ErrorHelper.CreateWarning (1052, $"Element {processedProperty.Name} is not generated as its name conflicts with other elements on the same class."));
continue;
}
Mapper.Register (processedProperty);
processedProperty.Freeze ();
yield return processedProperty;
}
}
protected IEnumerable<ProcessedProperty> PostProcessSubscriptProperties (IEnumerable<PropertyInfo> properties)
void ProcessPotentialName (ProcessedProperty processedProperty)
{
foreach (PropertyInfo property in properties) {
ProcessedProperty processedProperty = new ProcessedProperty (property, this);
string getSignature = processedProperty.HasGetter ? processedProperty.GetMethod.ObjCSignature : "";
string setSignature = processedProperty.HasSetter ? processedProperty.SetMethod.ObjCSignature : "";
if (RestrictedObjSelectors.IsImportantSelector (getSignature) || RestrictedObjSelectors.IsImportantSelector (setSignature)) {
string newName = "managed" + processedProperty.Name.PascalCase ();
Delayed.Add (ErrorHelper.CreateWarning (1051, $"Element {processedProperty.Name} is generated instead as {newName} because its name conflicts with an important objective-c selector."));
processedProperty.NameOverride = newName;
}
}
protected IEnumerable<ProcessedProperty> PostProcessSubscriptProperties (IEnumerable<ProcessedProperty> properties)
{
foreach (ProcessedProperty processedProperty in properties) {
if (Mapper.CheckForDuplicateSelectors (processedProperty) == DuplicationStatus.Unresolvable) {
Delayed.Add (ErrorHelper.CreateWarning (1052, $"Element {processedProperty.Name} is not generated as its name conflicts with other elements on the same class."));
continue;
}
Mapper.Register (processedProperty);
yield return processedProperty;
}
}
protected IEnumerable<ProcessedFieldInfo> PostProcessFields (IEnumerable<FieldInfo> fields)
void ProcessPotentialName (ProcessedFieldInfo processedField)
{
foreach (FieldInfo field in fields) {
ProcessedFieldInfo processedField = new ProcessedFieldInfo (field, this);
if (RestrictedObjSelectors.IsImportantSelector (processedField.GetterName) || RestrictedObjSelectors.IsImportantSelector (processedField.SetterName)) {
string newName = "managed" + processedField.Name.PascalCase ();
Delayed.Add (ErrorHelper.CreateWarning (1051, $"Element {processedField.Name} is generated instead as {newName} because its name conflicts with an important objective-c selector."));
processedField.NameOverride = newName;
}
}
protected IEnumerable<ProcessedFieldInfo> PostProcessFields (IEnumerable<ProcessedFieldInfo> fields)
{
foreach (ProcessedFieldInfo processedField in fields) {
ProcessPotentialName (processedField);
if (Mapper.CheckForDuplicateSelectors (processedField) == DuplicationStatus.Unresolvable) {
Delayed.Add (ErrorHelper.CreateWarning (1052, $"Element {processedField.Name} is not generated as its name conflicts with other elements on the same class."));
continue;
}
Mapper.Register (processedField);
yield return processedField;
}
}
protected IEnumerable<ProcessedConstructor> PostProcessConstructors (IEnumerable<ConstructorInfo> constructors)
protected IEnumerable<ProcessedConstructor> PostProcessConstructors (IEnumerable<ProcessedConstructor> constructors)
{
HashSet<string> duplicateNames = FindDuplicateNames (constructors);
foreach (ProcessedConstructor processedConstructor in constructors) {
if (Mapper.CheckForDuplicateSelectors (processedConstructor) == DuplicationStatus.Unresolvable)
continue;
foreach (ConstructorInfo constructor in constructors) {
ProcessedConstructor processedConstructor = new ProcessedConstructor (constructor, this);
if (duplicateNames.Contains (CreateStringRep(constructor)))
processedConstructor.FallBackToTypeName = true;
Mapper.Register (processedConstructor);
processedConstructor.Freeze ();
yield return processedConstructor;
}
}
}
static string CreateStringRep (ConstructorInfo constructor)
{
StringBuilder str = new StringBuilder ();
foreach (var arg in constructor.GetParameters ())
str.Append (arg.Name + ":"); // This format is arbitrary
return str.ToString ();
}
static class RestrictedNames
{
static readonly HashSet<string> Names = new HashSet<string> { "static", "auto" };
static string CreateStringRep (MethodInfo method)
public static bool IsRestrictedName (string name)
{
StringBuilder str = new StringBuilder (method.Name);
foreach (var arg in method.GetParameters ())
str.Append (":"); // This format is arbitrary
return str.ToString ();
}
static string CreateStringRep (MemberInfo i)
{
if (i is ConstructorInfo)
return CreateStringRep ((ConstructorInfo)i);
if (i is MethodInfo)
return CreateStringRep ((MethodInfo)i);
return i.Name;
}
// temporary quasi-duplicate
static HashSet<string> FindDuplicateNames (IEnumerable<ProcessedMethod> members)
{
Dictionary<string, int> methodNames = new Dictionary<string, int> ();
foreach (var member in members)
methodNames.IncrementValue (CreateStringRep (member.Method));
return new HashSet<string> (methodNames.Where (x => x.Value > 1).Select (x => x.Key));
}
static HashSet<string> FindDuplicateNames (IEnumerable<MemberInfo> members)
{
Dictionary<string, int> methodNames = new Dictionary<string, int> ();
foreach (MemberInfo member in members)
methodNames.IncrementValue (CreateStringRep (member));
return new HashSet<string> (methodNames.Where (x => x.Value > 1).Select (x => x.Key));
return Names.Contains (name);
}
}
static class RestrictedObjSelectors
{
static readonly HashSet<string> ImportantObjcSelectors = new HashSet<string> { "hash", "class", "superclass", "isEqual:", "self", "isKindOfClass:",
"isMemberOfClass:", "respondsToSelector:", "conformsToProtocol:", "description", "debugDescription", "performSelector:", "performSelector:withObject:",
"performSelector:withObject:withObject:", "isProxy", "retain", "release", "autorelease", "retainCount", "zone" };
static public bool IsImportantSelector (string selector)
{
if (selector.StartsWith ("get", StringComparison.Ordinal))
selector = selector.Substring (3).CamelCase ();
if (selector.StartsWith ("set", StringComparison.Ordinal)) {
selector = selector.Substring (3).CamelCase ();
int colonLocation = selector.IndexOf (':');
if (colonLocation > 0)
selector = selector.Substring (0, colonLocation);
}
return ImportantObjcSelectors.Contains (selector);
}
}
}

Просмотреть файл

@ -17,6 +17,8 @@ namespace Embeddinator.ObjC {
public override void Generate ()
{
Logger.Log ($"Begin Generator");
var types = Processor.Types;
headers.WriteLine ("#include \"embeddinator.h\"");
headers.WriteLine ("#import <Foundation/Foundation.h>");
@ -27,6 +29,10 @@ namespace Embeddinator.ObjC {
headers.WriteLine ("#endif");
headers.WriteLine ();
headers.WriteLine ("#ifdef __cplusplus");
headers.WriteLine ("extern \"C\" {");
headers.WriteLine ("#endif");
headers.WriteLine ("// forward declarations");
foreach (var t in types.Where ((arg) => arg.IsClass))
headers.WriteLine ($"@class {t.TypeName};");
@ -86,10 +92,16 @@ namespace Embeddinator.ObjC {
headers.WriteLine ("NS_ASSUME_NONNULL_END");
headers.WriteLine ();
headers.WriteLine ("#ifdef __cplusplus");
headers.WriteLine ("} /* extern \"C\" */");
headers.WriteLine ("#endif");
}
protected override void Generate (ProcessedAssembly a)
{
Logger.Log ($"Generating Assembly: {a.Name}");
var originalName = a.Name;
var name = a.SafeName;
implementation.WriteLine ($"static void __lookup_assembly_{name} ()");
@ -152,6 +164,8 @@ namespace Embeddinator.ObjC {
void GenerateCategory (Type definedType, Type extendedType, List<ProcessedMethod> methods)
{
Logger.Log ($"Generating Catagory: {definedType.Name}");
var etn = NameGenerator.GetTypeName (extendedType).Replace (" *", String.Empty);
var name = $"{etn} ({NameGenerator.GetTypeName (definedType)})";
headers.WriteLine ($"/** Category {name}");
@ -164,7 +178,7 @@ namespace Embeddinator.ObjC {
implementation.WriteLine ();
foreach (var mi in methods) {
ImplementMethod (mi.Method, mi.Method.Name.CamelCase (), mi, isExtension: true);
ImplementMethod (mi);
}
headers.WriteLine ("@end");
@ -176,6 +190,8 @@ namespace Embeddinator.ObjC {
void GenerateEnum (ProcessedType type)
{
Logger.Log ($"Generating Enum: {type.TypeName}");
Type t = type.Type;
var managed_name = type.ObjCName;
var underlying_type = t.GetEnumUnderlyingType ();
@ -216,6 +232,8 @@ namespace Embeddinator.ObjC {
void GenerateProtocol (ProcessedType type)
{
Logger.Log ($"Generating Protocol: {type.TypeName}");
Type t = type.Type;
var pbuilder = new ProtocolHelper (headers, implementation, private_headers) {
AssemblyQualifiedName = t.AssemblyQualifiedName,
@ -269,6 +287,8 @@ namespace Embeddinator.ObjC {
protected override void Generate (ProcessedType type)
{
Logger.Log ($"Generating Type: {type.TypeName}");
Type t = type.Type;
var aname = t.Assembly.GetName ().Name.Sanitize ();
var static_type = t.IsSealed && t.IsAbstract;
@ -304,11 +324,11 @@ namespace Embeddinator.ObjC {
default_init |= pcount == 0;
var parameters = ctor.Parameters;
string name = ctor.ObjCName;
string name = ctor.BaseName;
string signature = ".ctor()";
if (parameters.Length > 0) {
name = ctor.GetObjcSignature ();
signature = ctor.GetMonoSignature ();
name = ctor.ObjCSignature;
signature = ctor.MonoSignature;
}
if (ctor.Unavailable) {
@ -357,7 +377,7 @@ namespace Embeddinator.ObjC {
}
builder.WriteInvoke (args);
implementation.Write (postInvoke);
implementation.WriteLine ("_object = mono_embeddinator_create_object (__instance);");
implementation.WriteLine ("_object = (MonoEmbedObject *)mono_embeddinator_create_object (__instance);");
implementation.Indent--;
implementation.WriteLine ("}");
if (Processor.Types.HasClass (t.BaseType))
@ -392,7 +412,7 @@ namespace Embeddinator.ObjC {
implementation.Indent++;
implementation.WriteLine ($"MonoObject* __instance = mono_object_new (__mono_context.domain, {managed_name}_class);");
// no call to `WriteInvoke` since there is not such method if we reached this case
implementation.WriteLine ("_object = mono_embeddinator_create_object (__instance);");
implementation.WriteLine ("_object = (MonoEmbedObject *)mono_embeddinator_create_object (__instance);");
implementation.Indent--;
implementation.WriteLine ("}");
if (HasClass (t.BaseType))
@ -505,7 +525,8 @@ namespace Embeddinator.ObjC {
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
var ctype = NameGenerator.GetTypeName (t);
var ut = t.IsEnum ? t.GetEnumUnderlyingType () : t;
var ctype = NameGenerator.GetTypeName (ut);
string ctypep;
if (typecode == TypeCode.SByte)
ctypep = "Char"; // GetTypeName returns signed char
@ -518,6 +539,10 @@ namespace Embeddinator.ObjC {
postwriter.WriteLine ($"MonoDecimal {presarrval} = mono_array_get ({presarr}, MonoDecimal, {pindex});");
postwriter.WriteLine ($"{presobj} = mono_embeddinator_get_nsdecimalnumber (&{presarrval});");
break;
case TypeCode.DateTime:
postwriter.WriteLine ($"E4KDateTime {presarrval} = mono_array_get ({presarr}, E4KDateTime, {pindex});");
postwriter.WriteLine ($"{presobj} = mono_embeddinator_get_nsdate (&{presarrval});");
break;
case TypeCode.Byte:
postwriter.WriteLine ($"NSData* {presobj} = [NSData dataWithBytes:mono_array_addr ({presarr}, unsigned char, 0) length:{parrlength}];");
break;
@ -540,7 +565,7 @@ namespace Embeddinator.ObjC {
postwriter.WriteLine ($"if ({presarrval}) {{");
postwriter.Indent++;
postwriter.WriteLine ($"{tname}* {ptemp} = [[{tname} alloc] initForSuper];");
postwriter.WriteLine ($"{ptemp}->_object = mono_embeddinator_create_object ({presarrval});");
postwriter.WriteLine ($"{ptemp}->_object = (MonoEmbedObject *)mono_embeddinator_create_object ({presarrval});");
postwriter.WriteLine ($"{presobj} = {ptemp};");
postwriter.Indent--;
postwriter.WriteLine ("} else");
@ -614,10 +639,12 @@ namespace Embeddinator.ObjC {
case TypeCode.Double:
var typeName = NameGenerator.GetTypeName (type);
string returnValue;
if (typeCode == TypeCode.SByte)
if (typeCode == TypeCode.SByte) {
returnValue = $"charValue"; // GetTypeName returns signed char
else
returnValue = $"{typeName.CamelCase (true)}Value";
} else {
string returnValueTypeName = type.IsEnum ? NameGenerator.GetTypeName (type.GetEnumUnderlyingType ()) : typeName;
returnValue = $"{returnValueTypeName.CamelCase (true)}Value";
}
implementation.WriteLine ($"NSNumber* {pnameRet} = {(is_by_ref ? $"(*{parameterName})" : parameterName)}[{pnameIdx}];");
implementation.WriteLine ($"if (!{pnameRet} || [{pnameRet} isKindOfClass:[NSNull class]])");
@ -635,6 +662,15 @@ namespace Embeddinator.ObjC {
implementation.Indent--;
implementation.WriteLine ($"mono_array_set ({pnameArr}, MonoDecimal, {pnameIdx}, mono_embeddinator_get_system_decimal ({pnameRet}, &__mono_context));");
break;
case TypeCode.DateTime:
var dtparname = is_by_ref ? $"(*{parameterName})" : parameterName;
implementation.WriteLine ($"NSDate* {pnameRet} = {dtparname}[{pnameIdx}];");
implementation.WriteLine ($"if (!{pnameRet} || [{pnameRet} isKindOfClass:[NSNull class]])");
implementation.Indent++;
implementation.WriteLine ($"continue;");
implementation.Indent--;
implementation.WriteLine ($"mono_array_set ({pnameArr}, E4KDateTime, {pnameIdx}, mono_embeddinator_get_system_datetime ({pnameRet}, &__mono_context));");
break;
case TypeCode.String:
implementation.WriteLine ($"NSString* {pnameRet} = {(is_by_ref ? $"(*{parameterName})" : parameterName)}[{pnameIdx}];");
implementation.WriteLine ($"if (!{pnameRet} || [{pnameRet} isKindOfClass:[NSNull class]])");
@ -706,17 +742,23 @@ namespace Embeddinator.ObjC {
switch (Type.GetTypeCode (t)) {
case TypeCode.String:
if (is_by_ref) {
implementation.WriteLine ($"MonoString* __string = *{paramaterName} ? mono_string_new (__mono_context.domain, [*{paramaterName} UTF8String]) : nil;");
implementation.WriteLine ($"{argumentName} = &__string;");
post.AppendLine ($"*{paramaterName} = mono_embeddinator_get_nsstring (__string);");
implementation.WriteLine ($"MonoString* __string_{paramaterName} = *{paramaterName} ? mono_string_new (__mono_context.domain, [*{paramaterName} UTF8String]) : nil;");
implementation.WriteLine ($"{argumentName} = &__string_{paramaterName};");
post.AppendLine ($"*{paramaterName} = mono_embeddinator_get_nsstring (__string_{paramaterName});");
} else
implementation.WriteLine ($"{argumentName} = {paramaterName} ? mono_string_new (__mono_context.domain, [{paramaterName} UTF8String]) : nil;");
break;
case TypeCode.Decimal:
implementation.WriteLine ($"MonoDecimal __mdec = mono_embeddinator_get_system_decimal ({(is_by_ref ? "*" : string.Empty)}{paramaterName}, &__mono_context);");
implementation.WriteLine ($"{argumentName} = &__mdec;");
implementation.WriteLine ($"MonoDecimal __mdec_{paramaterName} = mono_embeddinator_get_system_decimal ({(is_by_ref ? "*" : string.Empty)}{paramaterName}, &__mono_context);");
implementation.WriteLine ($"{argumentName} = &__mdec_{paramaterName};");
if (is_by_ref)
post.AppendLine ($"*{paramaterName} = mono_embeddinator_get_nsdecimalnumber (&__mdec);");
post.AppendLine ($"*{paramaterName} = mono_embeddinator_get_nsdecimalnumber (&__mdec_{paramaterName});");
break;
case TypeCode.DateTime:
implementation.WriteLine ($"E4KDateTime __mdatetime_{paramaterName} = mono_embeddinator_get_system_datetime ({(is_by_ref ? "*" : string.Empty)}{paramaterName}, &__mono_context);");
implementation.WriteLine ($"{argumentName} = &__mdatetime_{paramaterName};");
if (is_by_ref)
post.AppendLine ($"*{paramaterName} = mono_embeddinator_get_nsdate (&__mdatetime_{paramaterName});");
break;
case TypeCode.Boolean:
case TypeCode.Char:
@ -751,37 +793,40 @@ namespace Embeddinator.ObjC {
protected override void Generate (ProcessedProperty property)
{
PropertyInfo pi = property.Property;
var getter = pi.GetGetMethod ();
var setter = pi.GetSetMethod ();
Logger.Log ($"Generating Property: {property.Name}");
var getter = property.GetMethod;
var setter = property.SetMethod;
// setter-only properties are handled as methods (and should not reach this code)
if (getter == null && setter != null)
throw new EmbeddinatorException (99, "Internal error `setter only`. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues");
var name = pi.Name.CamelCase ();
headers.Write ("@property (nonatomic");
if (getter.IsStatic)
if (getter.Method.IsStatic)
headers.Write (", class");
if (setter == null)
headers.Write (", readonly");
var pt = pi.PropertyType;
var pt = property.Property.PropertyType;
var property_type = NameGenerator.GetTypeName (pt);
if (pt.IsInterface)
property_type = $"id<{property_type}>";
if (HasClass (pt))
property_type += " *";
var spacing = property_type [property_type.Length - 1] == '*' ? string.Empty : " ";
headers.WriteLine ($") {property_type}{spacing}{name};");
headers.WriteLine ($") {property_type}{spacing}{property.Name};");
ImplementMethod (getter, name, property.GetMethod, pi: pi);
ImplementMethod (property.GetMethod);
if (setter == null)
return;
ImplementMethod (setter, "set" + pi.Name, property.SetMethod, pi: pi);
ImplementMethod (property.SetMethod);
}
protected void Generate (ProcessedFieldInfo field)
{
Logger.Log ($"Generating Field: {field.Name}");
FieldInfo fi = field.Field;
bool read_only = fi.IsInitOnly || fi.IsLiteral;
@ -799,10 +844,9 @@ namespace Embeddinator.ObjC {
if (bound)
field_type += " *";
var name = fi.Name.CamelCase ();
var spacing = field_type [field_type.Length - 1] == '*' ? string.Empty : " ";
headers.WriteLine ($") {field_type}{spacing}{name};");
headers.WriteLine ($") {field_type}{spacing}{field.Name};");
// it's similar, but different from implementing a method
@ -811,7 +855,7 @@ namespace Embeddinator.ObjC {
var return_type = GetReturnType (type, fi.FieldType);
implementation.Write (fi.IsStatic ? '+' : '-');
implementation.WriteLine ($" ({return_type}) {name}");
implementation.WriteLine ($" ({return_type}) {field.GetterName}");
implementation.WriteLine ("{");
implementation.Indent++;
implementation.WriteLine ("static MonoClassField* __field = nil;");
@ -845,7 +889,7 @@ namespace Embeddinator.ObjC {
if (read_only)
return;
implementation.Write (fi.IsStatic ? '+' : '-');
implementation.WriteLine ($" (void) set{fi.Name}:({field_type})value");
implementation.WriteLine ($" (void) {field.SetterName}:({field_type})value");
implementation.WriteLine ("{");
implementation.Indent++;
implementation.WriteLine ("static MonoClassField* __field = nil;");
@ -888,30 +932,32 @@ namespace Embeddinator.ObjC {
}
// TODO override with attribute ? e.g. [ObjC.Selector ("foo")]
// HACK - This should take a ProcessedMethod and not much of this stuff - https://github.com/mono/Embeddinator-4000/issues/276
string ImplementMethod (MethodInfo info, string name, ProcessedMethod method, bool isExtension = false, PropertyInfo pi = null)
string ImplementMethod (ProcessedMethod method)
{
Logger.Log ($"Generating Method Impl: {method}");
MethodInfo info = method.Method;
var type = info.DeclaringType;
var managed_type_name = NameGenerator.GetObjCName (type);
string objcsig = method.GetObjcSignature (name, isExtension);
string monosig = method.GetMonoSignature (info.Name);
string objcsig = method.ObjCSignature;
var builder = new MethodHelper (headers, implementation) {
AssemblySafeName = type.Assembly.GetName ().Name.Sanitize (),
IsStatic = info.IsStatic,
IsExtension = isExtension,
IsExtension = method.IsExtension,
ReturnType = GetReturnType (type, info.ReturnType),
ManagedTypeName = type.FullName,
MetadataToken = info.MetadataToken,
MonoSignature = monosig,
MonoSignature = method.MonoSignature,
ObjCSignature = objcsig,
ObjCTypeName = managed_type_name,
IsValueType = type.IsValueType,
IsVirtual = info.IsVirtual && !info.IsFinal,
};
if (pi == null)
if (!method.IsPropertyImplementation)
builder.WriteHeaders ();
builder.BeginImplementation ();
@ -921,7 +967,7 @@ namespace Embeddinator.ObjC {
string postInvoke = String.Empty;
var args = "nil";
if (parametersInfo.Length > 0) {
Generate (parametersInfo, isExtension, out postInvoke);
Generate (parametersInfo, method.IsExtension, out postInvoke);
args = "__args";
}
@ -936,6 +982,8 @@ namespace Embeddinator.ObjC {
void GenerateDefaultValuesWrapper (ProcessedMemberWithParameters member)
{
Logger.Log ($"Generating Default Value Wrapper: {member.ObjCSelector}");
ProcessedMethod method = member as ProcessedMethod;
ProcessedConstructor ctor = member as ProcessedConstructor;
if (method == null && ctor == null)
@ -963,9 +1011,8 @@ namespace Embeddinator.ObjC {
}
}
string name = method != null ? method.BaseName : ctor.ObjCName;
string objcsig = method != null ? method.GetObjcSignature () : ctor.GetObjcSignature ();
string monosig = method != null ? method.GetMonoSignature () : ctor.GetMonoSignature ();
string name = member.BaseName;
string objcsig = member.ObjCSignature;
var type = mb.DeclaringType;
@ -998,6 +1045,8 @@ namespace Embeddinator.ObjC {
protected override void Generate (ProcessedMethod method)
{
Logger.Log ($"Generating Method: {method}");
MethodHelper builder;
switch (method.MethodType) {
case MethodType.DefaultValueWrapper:
@ -1013,7 +1062,7 @@ namespace Embeddinator.ObjC {
builder = new EquatableHelper (method, headers, implementation);
break;
default:
ImplementMethod (method.Method, method.BaseName, method);
ImplementMethod (method);
return;
}
builder.WriteHeaders ();
@ -1051,7 +1100,8 @@ namespace Embeddinator.ObjC {
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
var ctype = NameGenerator.GetTypeName (t);
var dt = t.IsEnum ? t.GetEnumUnderlyingType () : t;
var ctype = NameGenerator.GetTypeName (dt);
string ctypep;
if (typecode == TypeCode.SByte)
ctypep = "Char"; // GetTypeName returns signed char
@ -1064,6 +1114,10 @@ namespace Embeddinator.ObjC {
implementation.WriteLine ($"MonoDecimal __resarrval = mono_array_get (__resarr, MonoDecimal, __residx);");
implementation.WriteLine ($"__resobj = mono_embeddinator_get_nsdecimalnumber (&__resarrval);");
break;
case TypeCode.DateTime:
implementation.WriteLine ($"E4KDateTime __resarrval = mono_array_get (__resarr, E4KDateTime, __residx);");
implementation.WriteLine ($"__resobj = mono_embeddinator_get_nsdate (&__resarrval);");
break;
case TypeCode.Byte:
implementation.WriteLine ("NSData* __resobj = [NSData dataWithBytes:mono_array_addr (__resarr, unsigned char, 0) length:__resarrlength];");
break;
@ -1086,7 +1140,7 @@ namespace Embeddinator.ObjC {
implementation.WriteLine ("if (__resarrval) {");
implementation.Indent++;
implementation.WriteLine ($"{tname}* __tmpobj = [[{tname} alloc] initForSuper];");
implementation.WriteLine ("__tmpobj->_object = mono_embeddinator_create_object (__resarrval);");
implementation.WriteLine ("__tmpobj->_object = (MonoEmbedObject *)mono_embeddinator_create_object (__resarrval);");
implementation.WriteLine ("__resobj = __tmpobj;");
implementation.Indent--;
implementation.WriteLine ("} else");
@ -1129,6 +1183,10 @@ namespace Embeddinator.ObjC {
implementation.WriteLine ("void* __unboxedresult = mono_object_unbox (__result);");
implementation.WriteLine ("return mono_embeddinator_get_nsdecimalnumber (__unboxedresult);");
break;
case TypeCode.DateTime:
implementation.WriteLine ("void* __unboxedresult = mono_object_unbox (__result);");
implementation.WriteLine ("return mono_embeddinator_get_nsdate ((E4KDateTime *)__unboxedresult);");
break;
case TypeCode.Boolean:
case TypeCode.Char:
case TypeCode.SByte:
@ -1160,7 +1218,7 @@ namespace Embeddinator.ObjC {
if (HasProtocol (t))
tname = "__" + tname + "Wrapper";
implementation.WriteLine ($"{tname}* __peer = [[{tname} alloc] initForSuper];");
implementation.WriteLine ("__peer->_object = mono_embeddinator_create_object (__result);");
implementation.WriteLine ("__peer->_object = (MonoEmbedObject *)mono_embeddinator_create_object (__result);");
implementation.WriteLine ("return __peer;");
break;
default:
@ -1249,6 +1307,8 @@ namespace Embeddinator.ObjC {
return string.Format (arrayCreator, $"{NameGenerator.GetObjCName (type)}_class");
case TypeCode.Decimal:
return string.Format (arrayCreator, "mono_embeddinator_get_decimal_class ()");
case TypeCode.DateTime:
return string.Format (arrayCreator, "mono_embeddinator_get_datetime_class ()");
default:
throw new NotImplementedException ($"Converting type {type.FullName} to mono class");
}

Просмотреть файл

@ -31,6 +31,7 @@ namespace Embeddinator.ObjC {
ProcessedType system_iformatprovider;
ProcessedType system_timespan;
ProcessedType system_globalization_timespanstyles;
ProcessedType system_datetime;
ProcessedAssembly GetMscorlib (Type t)
{
@ -62,13 +63,46 @@ namespace Embeddinator.ObjC {
var string_type = corlib.Assembly.GetType ("System.String");
var iformatprovider_type = corlib.Assembly.GetType ("System.IFormatProvider");
var parse = t.GetMethod ("Parse", new Type [] { string_type, iformatprovider_type });
system_decimal.Methods.Add (new ProcessedMethod (parse, this));
system_decimal.Methods.Add (new ProcessedMethod (parse, this, system_decimal));
var tostring = t.GetMethod ("ToString", new Type [] { iformatprovider_type });
system_decimal.Methods.Add (new ProcessedMethod (tostring, this));
system_decimal.Methods.Add (new ProcessedMethod (tostring, this, system_decimal));
AddExtraType (system_decimal);
return true;
}
bool AddDateTimeSupport (Type t)
{
if (system_datetime != null)
return true;
var corlib = GetMscorlib (t);
system_datetime = new ProcessedType (t) {
Assembly = corlib,
// this is tracked because the linker (if enabled) needs to be aware of the requirement
// but we do not want any code to be generated (it's referenced only from native/glue code)
IsNativeReference = true,
Methods = new List<ProcessedMethod> (),
Properties = new List<ProcessedProperty> (),
Constructors = new List<ProcessedConstructor> (),
};
var ticks = t.GetProperty ("Ticks");
system_datetime.Properties.Add (new ProcessedProperty (ticks, this, system_datetime));
var kind = t.GetProperty ("Kind");
system_datetime.Properties.Add (new ProcessedProperty (kind, this, system_datetime));
var dtk = corlib.Assembly.GetType ("System.DateTimeKind");
var longT = corlib.Assembly.GetType ("System.Int64");
var ctorLongKind = t.GetConstructor (new Type [] { longT, dtk });
system_datetime.Constructors.Add (new ProcessedConstructor (ctorLongKind, this, system_datetime));
var toUniversalTime = t.GetMethod ("ToUniversalTime");
system_datetime.Methods.Add (new ProcessedMethod (toUniversalTime, this, system_datetime));
AddExtraType (system_datetime);
return true;
}
bool IsSupported (Type t)
{
if (t.IsByRef)
@ -102,12 +136,10 @@ namespace Embeddinator.ObjC {
Delayed.Add (ErrorHelper.CreateWarning (1011, $"Type `{t}` is not generated because it lacks a native counterpart."));
unsupported.Add (t);
return false;
case "DateTime": // FIXME: NSDateTime
Delayed.Add (ErrorHelper.CreateWarning (1012, $"Type `{t}` is not generated because it lacks a marshaling code with a native counterpart."));
unsupported.Add (t);
return false;
case "Decimal":
return AddDecimalSupport (t);
case "DateTime":
return AddDateTimeSupport (t);
case "TimeSpan":
if (system_timespan == null) {
system_timespan = new ProcessedType (t) {
@ -160,8 +192,10 @@ namespace Embeddinator.ObjC {
}
}
protected IEnumerable<ConstructorInfo> GetConstructors (Type t)
protected IEnumerable<ProcessedConstructor> GetConstructors (ProcessedType processedType)
{
Type t = processedType.Type;
foreach (var ctor in t.GetConstructors ()) {
// .cctor not to be called directly by native code
if (ctor.IsStatic)
@ -182,7 +216,7 @@ namespace Embeddinator.ObjC {
if (!pcheck)
continue;
yield return ctor;
yield return new ProcessedConstructor (ctor, this, processedType);
}
}
@ -215,7 +249,7 @@ namespace Embeddinator.ObjC {
}
if (mi.Match ("System.Boolean", "Equals", "System.Object")) {
yield return new ProcessedMethod (mi, this) {
yield return new ProcessedMethod (mi, this, type) {
DeclaringType = type,
MethodType = MethodType.NSObjectProcotolIsEqual,
};
@ -223,7 +257,7 @@ namespace Embeddinator.ObjC {
}
if (implement_system_iequatable_t && mi.Match ("System.Boolean", "Equals", new string [] { null })) {
yield return new ProcessedMethod (mi, this) {
yield return new ProcessedMethod (mi, this, type) {
DeclaringType = type,
MethodType = MethodType.IEquatable,
};
@ -231,7 +265,7 @@ namespace Embeddinator.ObjC {
}
if (mi.Match ("System.Int32", "GetHashCode")) {
yield return new ProcessedMethod (mi, this) {
yield return new ProcessedMethod (mi, this, type) {
DeclaringType = type,
MethodType = MethodType.NSObjectProcotolHash,
};
@ -273,12 +307,12 @@ namespace Embeddinator.ObjC {
extmethods = new List<ProcessedMethod> ();
extensions.Add (extended_type, extmethods);
}
extmethods.Add (new ProcessedMethod (mi, this));
extmethods.Add (new ProcessedMethod (mi, this, type) { IsExtension = true } );
continue;
}
}
yield return new ProcessedMethod (mi, this);
yield return new ProcessedMethod (mi, this, type);
}
}
@ -294,9 +328,9 @@ namespace Embeddinator.ObjC {
}
}
protected IEnumerable<FieldInfo> GetFields (Type t)
protected IEnumerable<ProcessedFieldInfo> GetFields (ProcessedType t)
{
foreach (var fi in t.GetFields (BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly)) {
foreach (var fi in t.Type.GetFields (BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly)) {
if (!fi.IsPublic)
continue;
var ft = fi.FieldType;
@ -304,7 +338,7 @@ namespace Embeddinator.ObjC {
Delayed.Add (ErrorHelper.CreateWarning (1050, $"Field `{fi}` is not generated because of field type `{ft}` is not supported."));
continue;
}
yield return fi;
yield return new ProcessedFieldInfo (fi, this, t);
}
}
@ -317,7 +351,7 @@ namespace Embeddinator.ObjC {
bool extension_type;
public override void Process (IEnumerable<Assembly> input)
public override void Process (IEnumerable<ProcessedAssembly> input)
{
base.Process (input);
@ -327,7 +361,7 @@ namespace Embeddinator.ObjC {
// proceed with extra adjustments before giving results to the generator
foreach (var t in Types) {
foreach (var uctor in GetUnavailableParentCtors (t)) {
var c = new ProcessedConstructor (uctor.Constructor, this) { Unavailable = true };
var c = new ProcessedConstructor (uctor.Constructor, this, t) { Unavailable = true };
t.Constructors.Add (c);
}
}
@ -337,7 +371,7 @@ namespace Embeddinator.ObjC {
var pt = GetProcessedType (dv.DeclaringType);
var ci = dv as ConstructorInfo;
if (ci != null) {
foreach (var pc in AddDefaultValuesWrappers (ci)) {
foreach (var pc in AddDefaultValuesWrappers (ci, pt)) {
if (!pt.SignatureExists (pc))
pt.Constructors.Add (pc);
else
@ -346,7 +380,7 @@ namespace Embeddinator.ObjC {
continue;
}
var mi = dv as MethodInfo;
foreach (var pm in AddDefaultValuesWrappers (mi)) {
foreach (var pm in AddDefaultValuesWrappers (mi, pt)) {
if (!pt.SignatureExists (pm))
pt.Methods.Add (pm);
else
@ -359,6 +393,7 @@ namespace Embeddinator.ObjC {
public override void Process (ProcessedType pt)
{
Logger.Log ($"Processing Type: {pt.TypeName}");
Types.Add (pt);
if (pt.IsNativeReference)
return;
@ -373,7 +408,7 @@ namespace Embeddinator.ObjC {
implement_system_icomparable_t = t.Implements("System", "IComparable`1");
implement_system_iequatable_t = t.Implements ("System", "IEquatable`1");
var constructors = GetConstructors (t).OrderBy ((arg) => arg.GetParameters ().Length).ToList ();
var constructors = GetConstructors (pt).OrderBy ((arg) => arg.Constructor.GetParameters ().Length).ToList ();
var processedConstructors = PostProcessConstructors (constructors).ToList ();
pt.Constructors = processedConstructors;
@ -381,8 +416,8 @@ namespace Embeddinator.ObjC {
var processedMethods = PostProcessMethods (meths).ToList ();
pt.Methods = processedMethods;
var props = new List<PropertyInfo> ();
var subscriptProps = new List<PropertyInfo> ();
var props = new List<ProcessedProperty> ();
var subscriptProps = new List<ProcessedProperty> ();
foreach (var pi in GetProperties (t)) {
var getter = pi.GetGetMethod ();
var setter = pi.GetSetMethod ();
@ -392,14 +427,14 @@ namespace Embeddinator.ObjC {
// indexers are implemented as methods and object subscripting
if ((getter.GetParameters ().Length > 0) || ((setter != null) && setter.GetParameters ().Length > 1)) {
subscriptProps.Add (pi);
subscriptProps.Add (new ProcessedProperty (pi, this, pt));
continue;
}
// we can do better than methods for the more common cases (readonly and readwrite)
processedMethods.RemoveAll (x => x.Method == getter);
processedMethods.RemoveAll (x => x.Method == setter);
props.Add (pi);
props.Add (new ProcessedProperty (pi, this, pt));
}
props = props.OrderBy ((arg) => arg.Name).ToList ();
var processedProperties = PostProcessProperties (props).ToList ();
@ -413,7 +448,7 @@ namespace Embeddinator.ObjC {
}
// fields will need to be wrapped within properties
var f = GetFields (t).OrderBy ((arg) => arg.Name).ToList ();
var f = GetFields (pt).OrderBy ((arg) => arg.Name).ToList ();
var processedFields = PostProcessFields (f).ToList ();
pt.Fields = processedFields;
}
@ -449,14 +484,14 @@ namespace Embeddinator.ObjC {
return finalList;
}
IEnumerable<ProcessedConstructor> AddDefaultValuesWrappers (ConstructorInfo ci)
IEnumerable<ProcessedConstructor> AddDefaultValuesWrappers (ConstructorInfo ci, ProcessedType containingType)
{
// parameters with default values must be at the end and there can be many of them
var parameters = ci.GetParameters ();
for (int i = parameters.Length - 1; i >= 0; i--) {
if (!parameters [i].HasDefaultValue)
continue;
var pc = new ProcessedConstructor (ci, this) {
var pc = new ProcessedConstructor (ci, this, containingType) {
ConstructorType = ConstructorType.DefaultValueWrapper,
FirstDefaultParameter = i,
};
@ -464,14 +499,14 @@ namespace Embeddinator.ObjC {
}
}
IEnumerable<ProcessedMethod> AddDefaultValuesWrappers (MethodInfo mi)
IEnumerable<ProcessedMethod> AddDefaultValuesWrappers (MethodInfo mi, ProcessedType containingType)
{
// parameters with default values must be at the end and there can be many of them
var parameters = mi.GetParameters ();
for (int i = parameters.Length - 1; i >= 0; i--) {
if (!parameters [i].HasDefaultValue)
continue;
var pm = new ProcessedMethod (mi, this) {
var pm = new ProcessedMethod (mi, this, containingType) {
MethodType = MethodType.DefaultValueWrapper,
FirstDefaultParameter = i,
};

Просмотреть файл

@ -112,12 +112,16 @@ namespace Embeddinator.ObjC {
protected Processor Processor;
public bool FallBackToTypeName { get; set; }
public ProcessedType DeclaringType { get; set; }
public ProcessedMemberBase (Processor processor)
public ProcessedMemberBase (Processor processor, ProcessedType declaringType)
{
Processor = processor;
DeclaringType = declaringType;
}
public abstract IEnumerable<string> Selectors { get; }
// this format can be consumed by the linker xml files
// adapted from ikvm reflection and cecil source code
// FIXME: double check when we implement generics support
@ -150,45 +154,60 @@ namespace Embeddinator.ObjC {
}
public abstract class ProcessedMemberWithParameters : ProcessedMemberBase {
public ProcessedMemberWithParameters (Processor processor) : base (processor)
public ProcessedMemberWithParameters (Processor processor, ProcessedType declaringType) : base (processor, declaringType)
{
objCSignature = new CachedValue<string> (() => GetObjcSignature (true));
objCSelector = new CachedValue<string> (() => GetObjcSignature (false));
monoSignature = new CachedValue<string> (GetMonoSignature);
}
public abstract string BaseName { get; }
public ParameterInfo[] Parameters { get; protected set; }
public int FirstDefaultParameter { get; set; }
public string ObjCSignature { get; set; }
public string MonoSignature { get; set; }
protected abstract void ComputeSignatures ();
protected abstract string GetObjcSignature (bool includeParamNames);
int firstDefaultParameter;
public int FirstDefaultParameter {
get {
return firstDefaultParameter;
}
set {
firstDefaultParameter = value;
ComputeSignatures ();
}
public override IEnumerable<string> Selectors => ObjCSelector.Yield ();
CachedValue<string> objCSignature;
public string ObjCSignature => objCSignature.Value;
CachedValue<string> objCSelector;
public string ObjCSelector => objCSelector.Value;
protected abstract string GetMonoSignature ();
CachedValue<string> monoSignature;
public string MonoSignature => monoSignature.Value;
public void Freeze ()
{
objCSignature.Freeze ();
objCSelector.Freeze ();
monoSignature.Freeze ();
}
}
public class ProcessedMethod : ProcessedMemberWithParameters {
public MethodInfo Method { get; private set; }
public bool IsOperator { get; set; }
public string NameOverride { get; set; }
public bool IsPropertyImplementation { get; set; }
public string BaseName {
public string NameOverride { get; set; }
public string ManagedName { get; set; }
public override string BaseName {
get {
if (NameOverride != null)
return NameOverride;
return IsOperator? Method.Name.Substring (3).CamelCase () : Method.Name.CamelCase ();
return IsOperator ? Method.Name.Substring (3).CamelCase () : Method.Name.CamelCase ();
}
}
public MethodType MethodType { get; set; }
public ProcessedType DeclaringType { get; set; }
public bool IsExtension { get; set; }
public ProcessedMethod (MethodInfo method, Processor processor) : base (processor)
public ProcessedMethod (MethodInfo method, Processor processor, ProcessedType declaringType) : base (processor, declaringType)
{
Method = method;
MethodType = MethodType.Normal;
@ -196,20 +215,11 @@ namespace Embeddinator.ObjC {
FirstDefaultParameter = -1;
}
protected override void ComputeSignatures ()
{
ObjCSignature = GetObjcSignature ();
MonoSignature = GetMonoSignature ();
}
public override string ToString () => ToString (Method);
public string GetMonoSignature (string name = null)
protected override string GetMonoSignature ()
{
if (name == null)
name = BaseName;
var mono = new StringBuilder (name);
var mono = new StringBuilder (Method.Name);
mono.Append ('(');
@ -225,10 +235,10 @@ namespace Embeddinator.ObjC {
return mono.ToString ();
}
public string GetObjcSignature (string objName = null, bool isExtension = false)
protected override string GetObjcSignature (bool includeParamNames)
{
if (objName == null)
objName = BaseName;
string objName = BaseName;
if (Method.IsSpecialName)
objName = objName.Replace ("_", String.Empty);
@ -238,11 +248,13 @@ namespace Embeddinator.ObjC {
for (int n = 0; n < end; ++n) {
ParameterInfo p = Parameters[n];
if (objc.Length > objName.Length)
objc.Append (' ');
if (includeParamNames) {
if (objc.Length > objName.Length)
objc.Append (' ');
}
string paramName = FallBackToTypeName ? NameGenerator.GetParameterTypeName (p.ParameterType) : p.Name;
if (n > 0 || !isExtension) {
if (n > 0 || !IsExtension) {
if (n == 0) {
if (FallBackToTypeName || Method.IsConstructor || (!Method.IsSpecialName && !IsOperator))
objc.Append (paramName.PascalCase ());
@ -250,9 +262,13 @@ namespace Embeddinator.ObjC {
objc.Append (paramName.CamelCase ());
}
if (n > 0 || !isExtension) {
string ptname = NameGenerator.GetObjCParamTypeName (p, Processor.Types);
objc.Append (":(").Append (ptname).Append (")").Append (NameGenerator.GetExtendedParameterName (p, Parameters));
if (includeParamNames) {
if (n > 0 || !IsExtension) {
string ptname = NameGenerator.GetObjCParamTypeName (p, Processor.Types);
objc.Append (":(").Append (ptname).Append (")").Append (NameGenerator.GetExtendedParameterName (p, Parameters));
}
} else {
objc.Append (":");
}
}
@ -263,25 +279,70 @@ namespace Embeddinator.ObjC {
public class ProcessedProperty: ProcessedMemberBase {
public PropertyInfo Property { get; private set; }
public ProcessedProperty (PropertyInfo property, Processor processor) : base (processor)
public override IEnumerable<string> Selectors
{
get {
if (HasGetter)
yield return GetterName;
if (HasSetter)
yield return SetterName;
}
}
public ProcessedProperty (PropertyInfo property, Processor processor, ProcessedType declaringType) : base (processor, declaringType)
{
Property = property;
var g = Property.GetGetMethod ();
if (g != null)
GetMethod = new ProcessedMethod (g, Processor);
var s = Property.GetSetMethod ();
if (s != null)
SetMethod = new ProcessedMethod (s, Processor);
getMethod = new CachedValue<ProcessedMethod> (() => {
var getter = Property.GetGetMethod ();
if (getter != null) {
return new ProcessedMethod (getter, Processor, declaringType) { NameOverride = GetterName, IsPropertyImplementation = true };
}
return null;
});
setMethod = new CachedValue<ProcessedMethod> (() => {
var setter = Property.GetSetMethod ();
if (setter != null) {
return new ProcessedMethod (setter, Processor, declaringType) { NameOverride = SetterName, IsPropertyImplementation = true };
}
return null;
});
}
public override string ToString () => Property.ToString ();
public bool HasGetter => GetMethod != null;
public bool HasSetter => SetMethod != null;
public ProcessedMethod GetMethod { get; private set; }
public ProcessedMethod SetMethod { get; private set; }
public string Name => NameOverride != null ? NameOverride : Property.Name.CamelCase ();
public string NameOverride { get; set; }
public bool HasGetter => Property.GetGetMethod () != null;
public bool HasSetter => Property.GetSetMethod () != null;
public string GetterName {
get {
if (!HasGetter)
return null;
return (NameOverride ?? Property.Name).CamelCase ();
}
}
public string SetterName {
get {
if (!HasSetter)
return null;
return "set" + (NameOverride ?? Property.Name).PascalCase ();
}
}
CachedValue<ProcessedMethod> getMethod;
public ProcessedMethod GetMethod => getMethod.Value;
CachedValue<ProcessedMethod> setMethod;
public ProcessedMethod SetMethod => setMethod.Value;
public void Freeze ()
{
getMethod.Freeze ();
setMethod.Freeze ();
}
}
public enum ConstructorType {
@ -294,7 +355,7 @@ namespace Embeddinator.ObjC {
public ConstructorInfo Constructor { get; private set; }
public bool Unavailable { get; set; }
public string ObjCName {
public override string BaseName {
get {
if (Parameters.Length == 0 || FirstDefaultParameter == 0)
return "init";
@ -303,22 +364,16 @@ namespace Embeddinator.ObjC {
}
public ConstructorType ConstructorType { get; set; }
public ProcessedConstructor (ConstructorInfo constructor, Processor processor) : base (processor)
public ProcessedConstructor (ConstructorInfo constructor, Processor processor, ProcessedType declaringType) : base (processor, declaringType)
{
Constructor = constructor;
Parameters = Constructor.GetParameters ();
FirstDefaultParameter = -1;
}
protected override void ComputeSignatures ()
{
ObjCSignature = GetObjcSignature ();
MonoSignature = GetMonoSignature ();
}
public override string ToString () => ToString (Constructor);
public string GetMonoSignature ()
protected override string GetMonoSignature ()
{
var mono = new StringBuilder (Constructor.Name);
@ -336,16 +391,18 @@ namespace Embeddinator.ObjC {
return mono.ToString ();
}
public string GetObjcSignature ()
protected override string GetObjcSignature (bool includeParamNames)
{
var objc = new StringBuilder (ObjCName);
var objc = new StringBuilder (BaseName);
var end = FirstDefaultParameter == -1 ? Parameters.Length : FirstDefaultParameter;
for (int n = 0; n < end; ++n) {
ParameterInfo p = Parameters[n];
if (objc.Length > ObjCName.Length)
objc.Append (' ');
if (includeParamNames) {
if (objc.Length > BaseName.Length)
objc.Append (' ');
}
string paramName = FallBackToTypeName ? NameGenerator.GetParameterTypeName (p.ParameterType) : p.Name;
if (n == 0)
@ -353,8 +410,12 @@ namespace Embeddinator.ObjC {
else
objc.Append (paramName.CamelCase ());
string ptname = NameGenerator.GetObjCParamTypeName (p, Processor.Types);
objc.Append (":(").Append (ptname).Append (")").Append (NameGenerator.GetExtendedParameterName (p, Parameters));
if (includeParamNames) {
string ptname = NameGenerator.GetObjCParamTypeName (p, Processor.Types);
objc.Append (":(").Append (ptname).Append (")").Append (NameGenerator.GetExtendedParameterName (p, Parameters));
} else {
objc.Append (":");
}
}
return objc.ToString ();
@ -366,7 +427,17 @@ namespace Embeddinator.ObjC {
public string TypeName { get; private set; }
public string ObjCName { get; private set; }
public ProcessedFieldInfo (FieldInfo field, Processor processor) : base (processor)
public string Name => (NameOverride ?? Field.Name).CamelCase ();
public string NameOverride { get; set; }
public override IEnumerable<string> Selectors {
get {
yield return GetterName;
yield return SetterName;
}
}
public ProcessedFieldInfo (FieldInfo field, Processor processor, ProcessedType declaringType) : base (processor, declaringType)
{
Field = field;
TypeName = ObjC.NameGenerator.GetTypeName (Field.DeclaringType);
@ -375,5 +446,8 @@ namespace Embeddinator.ObjC {
// linker compatible signature
public override string ToString () => Field.FieldType.FullName + " " + Field.Name;
public string GetterName => (NameOverride ?? Field.Name).CamelCase ();
public string SetterName => "set" + (NameOverride ?? Field.Name).PascalCase ();
}
}

Просмотреть файл

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using IKVM.Reflection;
using Type = IKVM.Reflection.Type;
@ -16,16 +17,15 @@ namespace Embeddinator.ObjC {
protected List<Exception> Delayed = new List<Exception> ();
public virtual void Process (IEnumerable<Assembly> input)
public virtual void Process (IEnumerable<ProcessedAssembly> input)
{
Logger.Log ($"Processing: {input.Count ()} assemblies");
foreach (var a in input) {
var pa = new ProcessedAssembly (a) {
UserCode = true,
};
// ignoring/warning one is not an option as they could be different (e.g. different builds/versions)
if (!AddIfUnique (pa))
throw ErrorHelper.CreateError (12, $"The assembly name `{pa.Name}` is not unique");
assemblyQueue.Enqueue (pa);
if (!AddIfUnique (a))
throw ErrorHelper.CreateError (12, $"The assembly name `{a.Name}` is not unique");
assemblyQueue.Enqueue (a);
}
while (assemblyQueue.Count > 0) {
@ -41,6 +41,8 @@ namespace Embeddinator.ObjC {
if (!a.UserCode)
return;
Logger.Log ($"Processing Assembly: {a.Name}");
foreach (var t in GetTypes (a.Assembly)) {
var pt = new ProcessedType (t) {
Assembly = a,

Просмотреть файл

@ -12,6 +12,7 @@ while ! test -z $1; do
PROVISION_MONO=1
PROVISION_XI=1
PROVISION_XM=1
PROVISION_XCODE=1
shift
;;
--provision-mono)
@ -26,10 +27,15 @@ while ! test -z $1; do
PROVISION_XM=1
shift
;;
--provision-xcode)
PROVISION_XCODE=1
shift
;;
--provision-all)
PROVISION_MONO=1
PROVISION_XI=1
PROVISION_XM=1
PROVISION_XCODE=1
shift
;;
--ignore-mono)
@ -44,6 +50,10 @@ while ! test -z $1; do
IGNORE_XM=1
shift
;;
--ignore-xcode)
IGNORE_XCODE=1
shift
;;
*)
echo "Unknown argument: $1"
exit 1
@ -307,11 +317,39 @@ function check_xamarin_mac () {
ok "Found Xamarin.Mac $ACTUAL_XM_VERSION (at least $MIN_XM_VERSION and not more than $MAX_XM_VERSION is required)"
}
function check_xcode () {
if ! test -z $IGNORE_XCODE; then return; fi
if ! test -f /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/Version; then
if ! test -z $PROVISION_XI; then
install_xamarin_ios
else
fail "You must install Xamarin.iOS"
return
fi
fi
local CURRENT_XCODE_PATH=$(xcode-select -p)
local REQUESTED_XCODE=$(awk '/RecommendedXcodeVersion/{getline; print}' /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/Versions.plist | sed -e 's/<[^>]*>//g' | sed -e 's/\.//g' | xargs)
local NEEDED_XCODE_PATH=/Applications/Xcode$REQUESTED_XCODE.app/Contents/Developer
if test "$NEEDED_XCODE_PATH" != "$CURRENT_XCODE_PATH"; then
if ! test -z $PROVISION_XCODE; then
log "Setting selected xcode to $NEEDED_XCODE_PATH"
sudo xcode-select -s $NEEDED_XCODE_PATH
else
fail "You must set xcode-select to $NEEDED_XCODE_PATH"
return
fi
else
ok "Found Xcode $CURRENT_XCODE_PATH selected already"
fi
}
echo "Checking system..."
check_mono
check_xamarin_ios
check_xamarin_mac
check_xcode
if test -z $FAIL; then
echo "System check succeeded"

138
objcgen/utils.cs Normal file
Просмотреть файл

@ -0,0 +1,138 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace Embeddinator.ObjC
{
public static class Utils
{
public static bool RunProcess (string filename, string arguments, out int exitCode, out string stdout, bool capture_stderr = false)
{
Console.WriteLine ($"\t{filename} {arguments}");
var sb = new StringBuilder ();
var stdout_done = new System.Threading.ManualResetEvent (false);
var stderr_done = new System.Threading.ManualResetEvent (false);
using (var p = new Process ()) {
p.StartInfo.FileName = filename;
p.StartInfo.Arguments = arguments;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = capture_stderr;
p.OutputDataReceived += (sender, e) => {
if (e.Data == null) {
stdout_done.Set ();
}
else {
lock (sb)
sb.AppendLine (e.Data);
}
};
if (capture_stderr) {
p.ErrorDataReceived += (sender, e) => {
if (e.Data == null) {
stderr_done.Set ();
}
else {
lock (sb)
sb.AppendLine (e.Data);
}
};
}
p.Start ();
p.BeginOutputReadLine ();
if (capture_stderr)
p.BeginErrorReadLine ();
p.WaitForExit ();
stdout_done.WaitOne (TimeSpan.FromSeconds (1));
if (capture_stderr)
stderr_done.WaitOne (TimeSpan.FromSeconds (1));
stdout = sb.ToString ();
exitCode = p.ExitCode;
return exitCode == 0;
}
}
public static int RunProcess (string filename, string arguments)
{
int exitCode;
string output;
RunProcess (filename, arguments, out exitCode, out output, capture_stderr: true);
if (exitCode != 0)
Console.WriteLine (output);
return exitCode;
}
public static bool RunProcess (string filename, string arguments, out int exitCode)
{
exitCode = RunProcess (filename, arguments);
return exitCode == 0;
}
public static bool Xcrun (StringBuilder options, out int exitCode)
{
return RunProcess ("xcrun", options.ToString (), out exitCode);
}
public static bool Lipo (System.Collections.Generic.List<string> inputs, string output, out int exitCode)
{
Directory.CreateDirectory (Path.GetDirectoryName (output));
if (inputs.Count == 1) {
File.Copy (inputs[0], output, true);
exitCode = 0;
return true;
}
else {
var lipo_options = new StringBuilder ("lipo ");
foreach (var file in inputs)
lipo_options.Append (file).Append (" ");
lipo_options.Append ("-create -output ");
lipo_options.Append (Quote (output));
return Xcrun (lipo_options, out exitCode);
}
}
public static string Quote (string f)
{
if (f.IndexOf (' ') == -1 && f.IndexOf ('\'') == -1 && f.IndexOf (',') == -1 && f.IndexOf ('$') == -1)
return f;
var s = new StringBuilder ();
s.Append ('"');
foreach (var c in f) {
if (c == '"' || c == '\\')
s.Append ('\\');
s.Append (c);
}
s.Append ('"');
return s.ToString ();
}
// Mono.Unix can't create symlinks to relative paths, it insists on making the target a full path before creating the symlink.
[DllImport ("libc", SetLastError = true)]
static extern int symlink (string path1, string path2);
[DllImport ("libc")]
static extern int unlink (string pathname);
public static void CreateSymlink (string file, string target)
{
unlink (file);
var rv = symlink (target, file);
if (rv != 0)
throw ErrorHelper.CreateError (16, $"Could not create symlink '{file}' -> '{target}': error {Marshal.GetLastWin32Error ()}");
}
public static void FileCopyIfExists (string source, string target)
{
if (!File.Exists (source))
return;
File.Copy (source, target, true);
}
}
}

Просмотреть файл

@ -26,8 +26,10 @@
#pragma once
#ifdef __cplusplus
#if !defined (__OBJC__)
#include <cstdbool>
#include <cstdint>
#endif
#else
#include <stdbool.h>
#include <stdint.h>

Просмотреть файл

@ -105,7 +105,7 @@ ensure_capacity (GArrayPriv *priv, guint capacity)
new_capacity = (capacity + 63) & ~63;
priv->array.data = g_realloc (priv->array.data, element_length (priv, new_capacity));
priv->array.data = (gchar*) g_realloc (priv->array.data, element_length (priv, new_capacity));
if (priv->clear_) {
memset (element_offset (priv, priv->capacity),
@ -293,7 +293,7 @@ g_array_set_size (GArray *array, gint length)
#define GROW_IF_NECESSARY(s,l) { \
if(s->len + l >= s->allocated_len) { \
s->allocated_len = (s->allocated_len + l + 16) * 2; \
s->str = g_realloc(s->str, s->allocated_len); \
s->str = (char*)g_realloc(s->str, s->allocated_len); \
} \
}
@ -322,7 +322,7 @@ g_string_new_len (const gchar *init, gssize len)
ret->len = len < 0 ? strlen(init) : len;
ret->allocated_len = MAX(ret->len + 1, 16);
ret->str = g_malloc(ret->allocated_len);
ret->str = (char*)g_malloc(ret->allocated_len);
if (init)
memcpy(ret->str, init, ret->len);
ret->str[ret->len] = 0;
@ -341,7 +341,7 @@ g_string_sized_new (gsize default_size)
{
GString *ret = g_new (GString, 1);
ret->str = g_malloc (default_size);
ret->str = (char*)g_malloc (default_size);
ret->str [0] = 0;
ret->len = 0;
ret->allocated_len = default_size;

Просмотреть файл

@ -28,8 +28,13 @@
#include <stdint.h>
#include "embeddinator.h"
#ifdef __cplusplus
extern "C" {
#endif
#if defined (XAMARIN_IOS) || defined (XAMARIN_MAC)
#include <xamarin/xamarin.h>
typedef void * gpointer;
typedef uint16_t mono_unichar2;
@ -207,8 +212,8 @@ mono_threads_detach_coop (gpointer cookie, gpointer *dummy);
#endif
#ifndef MONODECIMAL
#define MONODECIMAL
#ifndef E4KDEFS
#define E4KDEFS
// from: https://github.com/mono/mono/blob/master/mono/metadata/decimal-ms.h
typedef struct {
@ -245,4 +250,18 @@ typedef struct {
} v;
} MonoDecimal;
typedef enum {
E4KDateTimeKind_Unspecified,
E4KDateTimeKind_Utc,
E4KDateTimeKind_Local
} E4KDateTimeKind;
typedef struct {
unsigned long long DateData;
} E4KDateTime;
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif

Просмотреть файл

@ -82,7 +82,7 @@ static gchar* strrchr_seperator (const gchar* filename)
#endif
char *p;
p = strrchr (filename, G_DIR_SEPARATOR);
p = (char*)strrchr (filename, G_DIR_SEPARATOR);
#ifdef G_OS_WIN32
p2 = strrchr (filename, '/');
if (p2 > p)
@ -334,7 +334,7 @@ void* mono_embeddinator_install_error_report_hook(mono_embeddinator_error_report
mono_embeddinator_error_report_hook_t prev = g_error_report_hook;
g_error_report_hook = hook;
return prev;
return (void*)prev;
}
void mono_embeddinator_error(mono_embeddinator_error_t error)
@ -390,3 +390,12 @@ MonoClass* mono_embeddinator_get_decimal_class ()
}
return decimalclass;
}
MonoClass* mono_embeddinator_get_datetime_class ()
{
static MonoClass* datetimeclass = 0;
if (!datetimeclass) {
datetimeclass = mono_class_from_name (mono_get_corlib (), "System", "DateTime");
}
return datetimeclass;
}

Просмотреть файл

@ -208,4 +208,10 @@ MonoObject* mono_embeddinator_get_cultureinfo_invariantculture_object ();
MONO_EMBEDDINATOR_API
MonoClass* mono_embeddinator_get_decimal_class ();
/**
* Gets DateTime MonoClass.
*/
MONO_EMBEDDINATOR_API
MonoClass* mono_embeddinator_get_datetime_class ();
MONO_EMBEDDINATOR_END_DECLS

Просмотреть файл

@ -51,5 +51,11 @@ NSDecimalNumber* mono_embeddinator_get_nsdecimalnumber (void* __unboxedresult);
MONO_EMBEDDINATOR_API
MonoDecimal mono_embeddinator_get_system_decimal (NSDecimalNumber* nsdecimalnumber, mono_embeddinator_context_t* context);
MONO_EMBEDDINATOR_API
E4KDateTime mono_embeddinator_get_system_datetime (NSDate* nsdate, mono_embeddinator_context_t* context);
MONO_EMBEDDINATOR_API
NSDate* mono_embeddinator_get_nsdate (E4KDateTime* datetime);
MONO_EMBEDDINATOR_END_DECLS

Просмотреть файл

@ -58,7 +58,7 @@ MonoObject* mono_embeddinator_get_object (id native, bool assertOnFailure)
NSLog (@"`%@` is not a managed instance and cannot be used like one", [native description]);
abort ();
}
int gchandle = (int) [native performSelector:@selector (xamarinGetGCHandle)];
long gchandle = (long) [native performSelector:@selector (xamarinGetGCHandle)];
return mono_gchandle_get_target (gchandle);
}
@ -146,3 +146,93 @@ MonoDecimal mono_embeddinator_get_system_decimal (NSDecimalNumber* nsdecimalnumb
return mdecimal;
}
// NSDate reference date 00:00:00 UTC on 1 January 2001
// https://developer.apple.com/reference/foundation/nsdate
#define NSDateRefDateTicks 631139040000000000LL
#define NetTicksPerSecond 10000000LL
#define DateTimeMaxValueTicks 3155378975999999999LL
#define DateTimeMinValueTicks 0LL
NSDate* mono_embeddinator_get_nsdate (E4KDateTime* datetime)
{
static MonoMethod* dtticksmethod = nil;
static MonoMethod* dtkindmethod = nil;
static MonoMethod* dttoutcmethod = nil;
MonoClass* datetimeclass = mono_embeddinator_get_datetime_class ();
if (!dtticksmethod)
dtticksmethod = mono_embeddinator_lookup_method ("System.DateTime:get_Ticks()", datetimeclass);
if (!dtkindmethod)
dtkindmethod = mono_embeddinator_lookup_method ("System.DateTimeKind:get_Kind()", datetimeclass);
MonoObject* kindex = nil;
MonoObject* kindboxed = mono_runtime_invoke (dtkindmethod, datetime, NULL, &kindex);
if (kindex)
mono_embeddinator_throw_exception (kindex);
E4KDateTimeKind kind = *(E4KDateTimeKind *) mono_object_unbox (kindboxed);
if (kind == E4KDateTimeKind_Local) {
if (!dttoutcmethod)
dttoutcmethod = mono_embeddinator_lookup_method ("System.DateTime:ToUniversalTime()", datetimeclass);
MonoObject* toutcex = nil;
MonoObject* utcdtboxed = mono_runtime_invoke (dttoutcmethod, datetime, NULL, &toutcex);
if (toutcex)
mono_embeddinator_throw_exception (toutcex);
datetime = (E4KDateTime*)mono_object_unbox (utcdtboxed);
}
MonoObject* ticks_ex = nil;
MonoObject* ticksboxed = mono_runtime_invoke (dtticksmethod, datetime, NULL, &ticks_ex);
if (ticks_ex)
mono_embeddinator_throw_exception (ticks_ex);
long long ticks = *(long long *) mono_object_unbox (ticksboxed);
NSTimeInterval seconds = (NSTimeInterval) (ticks - NSDateRefDateTicks) / NetTicksPerSecond;
NSDate* nsdate = [NSDate dateWithTimeIntervalSinceReferenceDate:seconds];
return nsdate;
}
E4KDateTime mono_embeddinator_get_system_datetime (NSDate* nsdate, mono_embeddinator_context_t* context)
{
static MonoMethod* datetimector = nil;
MonoClass* datetimeclass = mono_embeddinator_get_datetime_class ();
int utc = E4KDateTimeKind_Utc;
long long minvalueticks = DateTimeMinValueTicks;
void* datetimeargs [2];
long long nsdateinterval;
long long dateticks;
if (!nsdate)
datetimeargs [0] = &minvalueticks;
else {
nsdateinterval = [nsdate timeIntervalSinceReferenceDate];
dateticks = nsdateinterval * NetTicksPerSecond + NSDateRefDateTicks;
if (dateticks > DateTimeMaxValueTicks)
dateticks = DateTimeMaxValueTicks;
else if (dateticks < DateTimeMinValueTicks)
dateticks = DateTimeMinValueTicks;
datetimeargs [0] = &dateticks;
}
datetimeargs [1] = &utc;
if (!datetimector)
datetimector = mono_embeddinator_lookup_method ("System.DateTime:.ctor(long,System.DateTimeKind)", datetimeclass);
E4KDateTime datetime = { 0 };
MonoObject* ex = nil;
mono_runtime_invoke (datetimector, &datetime, datetimeargs, &ex);
if (ex)
mono_embeddinator_throw_exception (ex);
return datetime;
}

Просмотреть файл

@ -26,7 +26,7 @@ ALL_MANAGED_DLLS = \
$(TVOS_MANAGED_DLL) \
$(MACOS_MODERN_MANAGED_DLL) \
$(MACOS_FULL_MANAGED_DLL) \
$(MACOS_SYSTEM_MANAGED_DLL) \
$(MACOS_SYSTEM_MANAGED_DLL)
else
ALL_MANAGED_DLLS = \
$(GENERIC_MANAGED_DLL)

Просмотреть файл

@ -0,0 +1,10 @@
using System;
namespace Duplicates
{
public class WithRestrictedNamed
{
public bool Class { get; set; }
public int Hash () => 42;
}
}

Просмотреть файл

@ -42,5 +42,20 @@ namespace Enums {
i = i == IntEnum.Min ? IntEnum.Max : IntEnum.Min;
return ByteFlags.Bit5 | ByteFlags.Bit1;
}
public static int Count (IntEnum[] values)
{
return values == null ? 0 : values.Length;
}
// NSData is not ideal if `byte` is used as the underlying type
public static ByteEnum[] Bucket { get; set; }
}
public class github561 {
[Flags]
public enum ModeOfTransportW { Bus = 0b1, Tram = 0b10, Train = 0b100, }
public ModeOfTransportW[] ModesOfTransport { get; set; }
}
}

Просмотреть файл

@ -6,9 +6,9 @@ namespace Interfaces {
bool Boolean { get; }
string Convert (int integer);
string Convert (int value);
string Convert (long longint);
string Convert (long value);
}
// not public - only the contract is exposed thru a static type

Просмотреть файл

@ -35,6 +35,7 @@
<Compile Include="$(MSBuildThisFileDirectory)overloads.cs" />
<Compile Include="$(MSBuildThisFileDirectory)nestedClasses.cs" />
<Compile Include="$(MSBuildThisFileDirectory)arrays.cs" />
<Compile Include="$(MSBuildThisFileDirectory)duplicates.cs" />
<Compile Include="$(MSBuildThisFileDirectory)keywords.cs" />
<Compile Include="$(MSBuildThisFileDirectory)abstracts.cs" />
</ItemGroup>

Просмотреть файл

@ -136,7 +136,7 @@ namespace Methods {
public class DuplicateMethods {
public int DoIt () { return 42; }
public int DoIt (int i) { return 42; }
public int DoIt (string s) { return 42; }
public int DoIt (string i) { return 42; }
public int DoIt (int i, int j) { return 84; }
public bool Find (string name) { return true; }

Просмотреть файл

@ -81,14 +81,6 @@ public static class Type_String
public static string NonEmptyString { get { return "Hello World"; } }
}
/// <summary>
/// NOTE: DateTime types are not exposed, this is for verifying DateTime.Now works
/// </summary>
public static class Type_DateTime
{
public static string Now { get { return DateTime.Now.ToString(); } }
}
// objc: this type won't be generated (Exception is not supported) but the generation will succeed (with warnings)
public class MyException : Exception {
}
@ -124,3 +116,21 @@ public class ExposeExtraTypes {
get { return DateTime.Now.TimeOfDay; }
}
}
public static class Type_DateTime {
public static string Now { get { return DateTime.Now.ToString (); } }
public static DateTime ReturnDate (DateTime datetime) => datetime;
public static void RefDate (ref DateTime datetime) => datetime = DateTime.MinValue;
public static DateTime [] ReverseDates (DateTime [] dates) => dates?.Reverse ().ToArray ();
public static void ReverseRefDates (ref DateTime [] dates) => dates = dates?.Reverse ().ToArray ();
public static DateTime Max { get; } = DateTime.MaxValue;
public static DateTime Min { get; } = DateTime.MinValue;
public static bool Between (DateTime dt1, DateTime dt2)
{
var now = DateTime.Now;
return (now >= dt1) && (now <= dt2);
}
}

Просмотреть файл

@ -320,19 +320,19 @@
Fields_Struct *empty = [Fields_Struct empty];
XCTAssertNotNil (empty, "empty / struct static readonly");
XCTAssertNil ([empty class], "empty / class uninitialized");
XCTAssertNil ([empty managedClass], "empty / class uninitialized");
Fields_Struct *struct1 = [[Fields_Struct alloc] initWithEnabled:true];
XCTAssertTrue (struct1.boolean, "init / boolean / true");
struct1.boolean = false;
XCTAssertFalse (struct1.boolean, "init / boolean / set 1");
XCTAssertNotNil (struct1.class, "init / class initialized 1");
XCTAssertFalse (struct1.class.boolean, "init / class / boolean / default");
struct1.class = nil;
XCTAssertNil (struct1.class, "init / class set 1");
struct1.class = [[Fields_Class alloc] initWithEnabled:true];
XCTAssertTrue (struct1.class.boolean, "init / class / boolean / true");
XCTAssertNotNil (struct1.managedClass, "init / class initialized 1");
XCTAssertFalse (struct1.managedClass.boolean, "init / class / boolean / default");
struct1.managedClass = nil;
XCTAssertNil (struct1.managedClass, "init / class set 1");
struct1.managedClass = [[Fields_Class alloc] initWithEnabled:true];
XCTAssertTrue (struct1.managedClass.boolean, "init / class / boolean / true");
Fields_Struct *struct2 = [[Fields_Struct alloc] initWithEnabled:false];
XCTAssertNotNil ([struct2 class], "init / class initialized 2");
@ -507,7 +507,48 @@
NSArray<NSDecimalNumber *> *decimalrefNilarr = nil;
[Type_Decimal reverseDecimalArrRefDecArr:&decimalrefNilarr];
XCTAssertNil(decimalrefNilarr, "decimalrefNilarr");
XCTAssertNil (decimalrefNilarr, "decimalrefNilarr");
NSDate *distantFuture = [Type_DateTime returnDateDatetime:[NSDate distantFuture]];
XCTAssertNotNil (distantFuture, "distantFuture");
NSDate *verydistantFuture = [NSDate dateWithTimeIntervalSinceReferenceDate:[distantFuture timeIntervalSinceReferenceDate] * 8];
NSDate *netmaxverydistantFuture = [Type_DateTime returnDateDatetime:verydistantFuture];
NSDate *nsnetmax = [NSDate dateWithTimeIntervalSinceReferenceDate:(NSTimeInterval) 252423993600];
XCTAssertEqualWithAccuracy ([nsnetmax timeIntervalSinceReferenceDate], [netmaxverydistantFuture timeIntervalSinceReferenceDate], 0.001, "netmaxverydistantFuture");
NSDate *distantPast = [Type_DateTime returnDateDatetime:[NSDate distantPast]];
NSDate *nsnetmin = [NSDate dateWithTimeIntervalSinceReferenceDate:(NSTimeInterval) -63113904000];
XCTAssertEqualWithAccuracy ([nsnetmin timeIntervalSinceReferenceDate], [distantPast timeIntervalSinceReferenceDate], 0.001, "DateTime distantPast");
NSDate *netmax = Type_DateTime.max;
XCTAssertEqualWithAccuracy ([nsnetmax timeIntervalSinceReferenceDate], [netmax timeIntervalSinceReferenceDate], 0.001, "DateTime Max");
NSDate *netmin = Type_DateTime.min;
XCTAssertEqualWithAccuracy ([nsnetmin timeIntervalSinceReferenceDate], [netmin timeIntervalSinceReferenceDate], 0.001, "DateTime Min");
NSDate *refdate = nil;
[Type_DateTime refDateDatetime:&refdate];
XCTAssertEqualWithAccuracy ([nsnetmin timeIntervalSinceReferenceDate], [refdate timeIntervalSinceReferenceDate], 0.001, "DateTime refdate");
NSDate *nilTest = [Type_DateTime returnDateDatetime:nil];
XCTAssertEqualWithAccuracy ([nsnetmin timeIntervalSinceReferenceDate], [nilTest timeIntervalSinceReferenceDate], 0.001, "DateTime nilTest");
NSArray<NSDate *> *datesArr = @[netmax, netmin];
[Type_DateTime reverseRefDatesDates:&datesArr];
XCTAssertEqualWithAccuracy ([nsnetmin timeIntervalSinceReferenceDate], [datesArr[0] timeIntervalSinceReferenceDate], 0.001, "DateTime reverseRefDatesDates Min");
XCTAssertEqualWithAccuracy ([nsnetmax timeIntervalSinceReferenceDate], [datesArr[1] timeIntervalSinceReferenceDate], 0.001, "DateTime reverseRefDatesDates Max");
NSArray<NSDate *> *revdatesArr = [Type_DateTime reverseDatesDates:@[netmax, netmin]];
XCTAssertEqualWithAccuracy ([nsnetmin timeIntervalSinceReferenceDate], [revdatesArr[0] timeIntervalSinceReferenceDate], 0.001, "DateTime reverseDatesDates Min");
XCTAssertEqualWithAccuracy ([nsnetmax timeIntervalSinceReferenceDate], [revdatesArr[1] timeIntervalSinceReferenceDate], 0.001, "DateTime reverseDatesDates Max");
NSArray<NSDate *> *refnilarrdate = nil;
[Type_DateTime reverseRefDatesDates:&refnilarrdate];
XCTAssertNil (refnilarrdate, "DateTime refnilarrdate");
NSArray<NSDate *> *revdatesnillArr = [Type_DateTime reverseDatesDates:nil];
XCTAssertNil (revdatesnillArr, "DateTime revdatesnillArr");
}
- (void) testObjectIndexedSubscripting {
@ -1313,6 +1354,12 @@
}
}
- (void)testRestrictedNames {
Duplicates_WithRestrictedNamed * d = [[Duplicates_WithRestrictedNamed alloc] init];
Class c = [d class];
XCTAssertNotEqual(42, [d hash], "Must not call instance Hash ()");
}
#pragma clang diagnostic pop
@end

Просмотреть файл

@ -41,7 +41,7 @@ namespace DriverTest
int exitCode;
Console.WriteLine ($"{filename} {arguments}");
// We capture stderr too, otherwise it won't show up in the test unit pad's output.
if (Embedder.RunProcess (filename, arguments, out exitCode, out stdout, capture_stderr: true))
if (Utils.RunProcess (filename, arguments, out exitCode, out stdout, capture_stderr: true))
return;
Console.WriteLine ($"Command failed with exit code: {exitCode}");
Console.WriteLine (stdout);

Просмотреть файл

@ -193,7 +193,7 @@ namespace DriverTest {
var csfile = Path.Combine (tmpdir, "foo.cs");
var dllfile = Path.Combine (tmpdir, "foo.dll");
File.WriteAllText (csfile, @"public class C { public Foundation.NSObject F () { throw new System.NotImplementedException (); } }");
Asserts.RunProcess ("/Library/Frameworks/Mono.framework/Commands/csc", $"/target:library /out:{Embedder.Quote (dllfile)} {Embedder.Quote (csfile)} -r:/Library/Frameworks/Xamarin.iOS.framework/Versions/Current/lib/mono/Xamarin.iOS/Xamarin.iOS.dll", "compile dll");
Asserts.RunProcess ("/Library/Frameworks/Mono.framework/Commands/csc", $"/target:library /out:{Utils.Quote (dllfile)} {Utils.Quote (csfile)} -r:/Library/Frameworks/Xamarin.iOS.framework/Versions/Current/lib/mono/Xamarin.iOS/Xamarin.iOS.dll", "compile dll");
Asserts.ThrowsEmbeddinatorException (13, "Can't find the assembly 'Xamarin.iOS, Version=0.0.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065', referenced by 'foo, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.", () => Driver.Main2 (dllfile, "--platform=tvOS", "--outdir=" + tmpdir));
}
}

Просмотреть файл

@ -48,7 +48,7 @@ namespace DriverTest
string output;
int exitCode;
Assert.IsTrue (Embedder.RunProcess ("xcrun", $"lipo -info {tmpdir}/libLibrary.dylib", out exitCode, out output), "lipo");
Assert.IsTrue (Utils.RunProcess ("xcrun", $"lipo -info {tmpdir}/libLibrary.dylib", out exitCode, out output), "lipo");
StringAssert.IsMatch ($"Non-fat file: .* is architecture: {abi}", output, "architecture");
}
@ -91,7 +91,7 @@ namespace DriverTest
File.WriteAllText (cs_path, code);
if (!Embedder.RunProcess ("/Library/Frameworks/Mono.framework/Versions/Current/bin/csc", $"/target:library {Embedder.Quote (cs_path)} /out:{Embedder.Quote (dll_path)}", out exitCode))
if (!Utils.RunProcess ("/Library/Frameworks/Mono.framework/Versions/Current/bin/csc", $"/target:library {Utils.Quote (cs_path)} /out:{Utils.Quote (dll_path)}", out exitCode))
Assert.Fail ("Failed to compile test code");
return dll_path;

Просмотреть файл

@ -1,4 +1,4 @@
run-tests:
nuget restore ../../generator.sln
nuget restore ../../Embeddinator-4000.sln
msbuild objcgentest.csproj
mono --debug ../../packages/NUnit.ConsoleRunner.3.6.1/tools/nunit3-console.exe bin/Debug/objcgentest.dll "--result=$(abspath $(CURDIR)/TestResult.xml);format=nunit2"

Просмотреть файл

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using Embeddinator.ObjC;
@ -10,6 +11,7 @@ using Xamarin;
using DriverTest;
using NUnit.Framework;
using NUnit.Framework.Interfaces;
namespace ExecutionTests
{
@ -72,7 +74,7 @@ namespace ExecutionTests
[TestCase (false)]
public void tvOS_simulator (bool debug)
{
RunManagedTests (Platform.tvOS, "-destination 'platform=tvOS Simulator,name=Apple TV 1080p,OS=latest'", debug: debug);
RunManagedTests (Platform.tvOS, "-destination 'platform=tvOS Simulator,name=Apple TV 4K (at 1080p),OS=latest'", debug: debug);
}
[Test]
@ -92,11 +94,19 @@ namespace ExecutionTests
if (device_xml == null) {
var cachedir = Cache.CreateTemporaryDirectory ();
var xmlpath = Path.Combine (cachedir, "devices.xml");
Asserts.RunProcess ("/Library/Frameworks/Xamarin.iOS.framework/Versions/Current/bin/mlaunch", $"--listdev={Embedder.Quote (xmlpath)} --output-format=xml", "mlaunch --listdev");
Asserts.RunProcess ("/Library/Frameworks/Xamarin.iOS.framework/Versions/Current/bin/mlaunch", $"--listdev={Utils.Quote (xmlpath)} --output-format=xml", "mlaunch --listdev");
var settings = new XmlReaderSettings () {
XmlResolver = null,
DtdProcessing = DtdProcessing.Parse
};
device_xml = new XmlDocument ();
device_xml.Load (xmlpath);
var sr = new StreamReader (xmlpath, Encoding.UTF8, true);
var reader = XmlReader.Create (sr, settings);
device_xml.Load (reader);
}
var nodes = device_xml.SelectNodes ("/MTouch/Device[" + string.Join (" or ", valid_classes.Select ((v) => "DeviceClass = \"" + v + "\"")) + "]/DeviceIdentifier");
// filter by device type and ensure that we can use the device for debugging purposes.
var xpathQuery = "/MTouch/Device[(" + string.Join(" or ", valid_classes.Select((v) => "DeviceClass = \"" + v + "\"")) + ") and IsUsableForDebugging =\"True\"]/DeviceIdentifier";
var nodes = device_xml.SelectNodes (xpathQuery);
var devices = new List<string> ();
foreach (XmlNode node in nodes)
devices.Add (node.InnerText);
@ -197,7 +207,7 @@ namespace ExecutionTests
var dll_path = Path.Combine (XcodeProjectGenerator.TestsRootDirectory, "managed", dlldir, "bin", configuration, dllname);
// This will build all the managed.dll variants, which is easier than calculating the relative path _as the makefile sees it_ to pass as the target.
Asserts.RunProcess ("make", $"all CONFIG={configuration} -C {Embedder.Quote (Path.Combine (XcodeProjectGenerator.TestsRootDirectory, "managed"))}", "build " + Path.GetFileName (dll_path));
Asserts.RunProcess ("make", $"all CONFIG={configuration} -C {Utils.Quote (Path.Combine (XcodeProjectGenerator.TestsRootDirectory, "managed"))}", "build " + Path.GetFileName (dll_path));
var outdir = tmpdir + "/out";
var projectName = "foo";
@ -217,7 +227,7 @@ namespace ExecutionTests
string output;
var builddir = Path.Combine (tmpdir, "xcode-build-dir");
Asserts.RunProcess ("xcodebuild", $"test -project {Embedder.Quote (projectDirectory)} -scheme Tests {test_destination} CONFIGURATION_BUILD_DIR={Embedder.Quote (builddir)}", out output, "run xcode tests");
Asserts.RunProcess ("xcodebuild", $"test -project {Utils.Quote (projectDirectory)} -scheme Tests {test_destination} CONFIGURATION_BUILD_DIR={Utils.Quote (builddir)}", out output, "run xcode tests");
// assert the number of tests passed, so that we can be sure we actually ran all the tests. Otherwise it's very easy to ignore when a bug is causing tests to not be built.
Assert.That (output, Does.Match ($"Test Suite 'All tests' passed at .*\n\t Executed {managedTestCount} tests, with 0 failures"), "test count");
}

Просмотреть файл

@ -161,7 +161,7 @@ namespace ObjCGenErrWarnTests {
clangArgs.Append ($"-o {Path.Combine (tempWorkingDir, "foo.o")} ");
// Embedder.RunProcess returns false if exitcode != 0
Assert.IsFalse (Embedder.RunProcess ("xcrun", clangArgs.ToString (), out int exitCode, out string output, capture_stderr: true), "clangbuild");
Assert.IsFalse (Utils.RunProcess ("xcrun", clangArgs.ToString (), out int exitCode, out string output, capture_stderr: true), "clangbuild");
Assert.That (output, Does.Contain (errorToSearch), $"Not found: {errorToSearch}");
}
}

Просмотреть файл

@ -38,7 +38,7 @@ namespace ObjCGeneratorTest {
[Test]
public void TypeMatchFailure ()
{
Assert.Throws<NotImplementedException> (() => NameGenerator.GetTypeName (mscorlib.GetType ("System.DateTime")), "DateTime");
Assert.Throws<NotImplementedException> (() => NameGenerator.GetTypeName (mscorlib.GetType ("System.DBNull")), "DBNull");
}
[Test]