Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Move dlopen and dlsym to PAL #25134

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/Common/src/Interop/Unix/System.Native/Interop.DlOpen.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class Sys
{
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_DlOpen")]
internal static extern IntPtr DlOpen(string fileName, DlOpenFlags flag);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class Sys
{
[DllImport(Libraries.Libdl, EntryPoint = "dlopen")]
internal static extern IntPtr DlOpen(string fileName, DlOpenFlags flag);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
using System;
using System.Runtime.InteropServices;

internal partial class Interop
internal static partial class Interop
{
internal partial class Libdl
internal static partial class Sys
{
[DllImport(Libraries.Libdl)]
public static extern IntPtr dlsym(IntPtr handle, string symbol);
[Flags]
internal enum DlOpenFlags : int
{
RTLD_LAZY = 1,
RTLD_NOW = 2
}
}
}
15 changes: 15 additions & 0 deletions src/Common/src/Interop/Unix/System.Native/Interop.DlSym.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class Sys
{
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_DlSym")]
internal static extern IntPtr DlSym(IntPtr handle, string symbol);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@
using System;
using System.Runtime.InteropServices;

internal partial class Interop
internal static partial class Interop
{
internal partial class Libdl
internal static partial class Sys
{
public const int RTLD_NOW = 0x002;

[DllImport(Libraries.Libdl)]
public static extern IntPtr dlopen(string fileName, int flag);
[DllImport(Libraries.Libdl, EntryPoint = "dlsym")]
internal static extern IntPtr DlSym(IntPtr handle, string symbol);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ namespace System.Runtime.InteropServices
internal static partial class FunctionWrapper
{
public static IntPtr LoadFunctionPointer(IntPtr nativeLibraryHandle, string functionName)
=> Interop.Libdl.dlsym(nativeLibraryHandle, functionName);
=> Interop.Sys.DlSym(nativeLibraryHandle, functionName);
}
}
1 change: 1 addition & 0 deletions src/Native/Unix/System.Native/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ set(NATIVE_SOURCES
pal_uid.cpp
pal_datetime.cpp
pal_sysctl.cpp
pal_dl.cpp
)

if (CMAKE_SYSTEM_NAME STREQUAL Linux)
Expand Down
20 changes: 20 additions & 0 deletions src/Native/Unix/System.Native/pal_dl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#include <dlfcn.h>
#include "pal_dl.h"

// Validate that our definitions match those used by the OS.
static_assert(PAL_RTLD_LAZY == RTLD_LAZY, "");
static_assert(PAL_RTLD_NOW == RTLD_NOW, "");

extern "C" void* SystemNative_DlOpen(const char *file, int mode)
{
return dlopen(file, mode);
}

extern "C" void* SystemNative_DlSym(void *handle, const char *name)
{
return dlsym(handle, name);
}
26 changes: 26 additions & 0 deletions src/Native/Unix/System.Native/pal_dl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#pragma once

// Values for the mode flag in dlopen
enum
{
PAL_RTLD_LAZY = 1,
PAL_RTLD_NOW = 2
};

/**
* Loads a dynamic library file. Implemented as shim to dlopen(3).
*
* An opaque handle for the dynamic library, or null on failure.
*/
extern "C" void* SystemNative_DlOpen(const char *file, int mode);

/**
* Gets, for a given dynamic library, the address of a symbol in that library. Implemented as shim to dlopen(3).
*
* The address of the symbol, or null on failure.
*/
extern "C" void* SystemNative_DlSym(void *handle, const char *name);
4 changes: 2 additions & 2 deletions src/System.Data.Odbc/tests/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ public static class Helpers
private static bool CheckOdbcIsAvailable() =>
PlatformDetection.IsWindows ?
!PlatformDetection.IsWindowsNanoServer && (!PlatformDetection.IsWindowsServerCore || Environment.Is64BitProcess ) :
Interop.Libdl.dlopen((
Interop.Sys.DlOpen((
PlatformDetection.IsOSX ?
"libodbc.2.dylib" :
"libodbc.so.2"
), Interop.Libdl.RTLD_NOW) != IntPtr.Zero;
), Interop.Sys.DlOpenFlags.RTLD_NOW) != IntPtr.Zero;
}
}
7 changes: 5 additions & 2 deletions src/System.Data.Odbc/tests/System.Data.Odbc.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@
<Compile Include="$(CommonPath)\Interop\Unix\Interop.Libraries.cs">
<Link>Common\Interop\Unix\Interop.Libraries.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Unix\libdl\Interop.dlopen.cs">
<Link>Common\Interop\Unix\libdl\Interop.dlopen.cs</Link>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.DlOpen.cs">
<Link>Common\Interop\Unix\libdl\Interop.DlOpen.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.DlOpenFlags.cs">
<Link>Common\Interop\Unix\libdl\Interop.DlOpenFlags.cs</Link>
</Compile>
<Compile Include="TestCommon\DataTestUtility.cs" />
<Compile Include="TestCommon\CheckConnStrSetupFactAttribute.cs" />
Expand Down
7 changes: 6 additions & 1 deletion src/System.Drawing.Common/src/Configurations.props
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildConfigurations>
<PackageConfigurations>
netcoreapp2.0-Windows_NT;
netcoreapp2.0-Unix;
netfx;
netstandard;
</PackageConfigurations>
<BuildConfigurations>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is turning System.Drawing.Common into yet another partial OOB, with unmanaged dependency. Partial OOBs like that have very high maintenance costs. If we want to do this, it should be approved by the .NET Core disro owners.
cc @Petermarcu @karelz

The right way to solve the problem with PInvoking to DlOpen is to add the imperative dll import APIs to .NET Core 2.1: https://github.com/dotnet/coreclr/issues/14968. It will avoid the need for the dependency on .NE T Core shims, and putting System.Drawing.Common inbox.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jkotas, won't it be a partial OOB either way? A build for 2.0 on top of standard, and then a build for 2.1 using netcoreapp-specific APIs. How does a dependency on a System.Native.so/dylib function cause any more issues than a dependency on netcoreapp-specific method?

Copy link
Member

@jkotas jkotas Nov 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The difference is whether it is part of .NET Runtime download or whether the app carries it with itself.

Everything that depends on System.Native.so/dylib shim should be part of .NET Runtime download. The System.Native.so/dylib shim is not part of our public API surface.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think dotnet/coreclr#14968 will solve the problem this PR is trying to address.

Yes, there are a lot of cases where managed code wants to have a lot of control over which library is being loaded. Managed libraries which wrap around native libraries, for example, will know where their native library is located, what name(s) it may have, and will try to load that directly.
For example, I think it's normal System.Drawing.Common has a very strong opinion about where libgdiplus.so is located, because it has domain knowledge about libgdiplus. The same for, say, FFmpeg.AutoGen, which is a managed wrapper around ffmpeg.

On the other hand, System.Drawing.Common doesn't care at all about dlopen and has no domain knowledge about it. The way I understand it, dotnet/coreclr#14968 would allow System.Drawing.Common to say something along the lines of "dlopen may be in libdl.so on most Linux distro's, libdl.so.2 on CentOS and something else on FreeBSD".

I don't think it's the business of System.Drawing.Common to care about that.

Anyone writing a managed wrapper around a native library trying and using function pointers will need dlopen and dlsym. Everyone doing that will need to replicate the same search logic.
And most importantly, that logic will eventually fail: when corefx is ported to a new platform, when libdl versions,... .

Long story short, for this use case, I believe a better option would be to make dlopen/dlsym in one shape or another part of the CoreFX API, as suggested in #17135.

"The least that could possible work" may be to expose a public LoadNativeLibrary and LoadNativeSymbol API in CoreFX on which System.Drawing.Common and others can depend.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe a better option would be to make dlopen/dlsym in one shape or another part of the CoreFX API, as suggested in #17135.

Agree. I did not know that #17135 existed. The APIs proposed by #17135 are the kind of APIs that I thought we will add as part of dotnet/coreclr#14968.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If nuget package declares dependency on netcore2.1, it is expected to work on netcoreapp2.2 or even netcoreapp3.0 as well. How do we make sure that it works there when it depends on netcoreapp2.1 shims?

Copy link
Member

@stephentoub stephentoub Nov 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do we make sure that it works there when it depends on netcoreapp2.1 shims?

By taking such a dependency we're signing up to keep those functions exposed, as part of the internal surface area of the product, little different than signing up to continue keeping public surface area exposed in subsequent versions.

Like I said earlier, I'm fine if we decide against that and want to impose the restrictions you highlight. I'm simply calling out that I don't think it's the only avenue available to us.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree.

The difference is that we have a lot of infrastructure to maintain compatibility of the public surface. Such infrastructure does not exist for the internal surface. It would need to be built.

We have tried to play similar internal surface games in .NET Framework in the past (e.g. with System.SizedReference). It tends to turn into poorly designed, tested and documented part that everybody is afraid to touch. I would love to keep things simple and stick to public surface when it comes to dependencies between independent packages.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The difference is that we have a lot of infrastructure to maintain compatibility of the public surface.

Fair enough.

I would love to keep things simple and stick to public surface when it comes to dependencies between independent packages.

Ok.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW I agree with @jkotas that we should avoid taking these type of dependencies in independent shipping packages. While the rule likely isn't written down anywhere we do try to follow the same strategy for anything the depends on System.Private.CoreLib directly as well.

$(PackageConfigurations);
netcoreapp-Windows_NT;
netcoreapp-Unix;
</BuildConfigurations>
</PropertyGroup>
</Project>
45 changes: 32 additions & 13 deletions src/System.Drawing.Common/src/System.Drawing.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Unix-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp2.0'">
<ItemGroup Condition="$(TargetGroup.Contains('netcoreapp'))">
<!-- Shared source code, all configurations -->
<Compile Include="misc\InvalidEnumArgumentException.cs" />
<Compile Include="System\Drawing\BitmapSuffixInSameAssemblyAttribute.cs" />
<Compile Include="System\Drawing\BitmapSuffixInSatelliteAssemblyAttribute.cs" />
<Compile Include="System\Drawing\Brushes.cs" />
Expand Down Expand Up @@ -175,9 +178,6 @@
<Compile Include="$(CommonPath)\System\Drawing\ColorUtil.netcoreapp20.cs">
<Link>System\Drawing\ColorUtil.netcoreapp20.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Drawing\KnownColor.cs">
<Link>System\Drawing\KnownColor.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Drawing\KnownColorTable.cs">
<Link>System\Drawing\KnownColorTable.cs</Link>
</Compile>
Expand All @@ -192,7 +192,13 @@
<LogicalName>System.Drawing.ShieldIcon.ico</LogicalName>
</EmbeddedResource>
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp2.0' AND '$(TargetsWindows)' == 'true'">
<ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp2.0'">
<Compile Include="misc\InvalidEnumArgumentException.cs" />
<Compile Include="$(CommonPath)\System\Drawing\KnownColor.cs">
<Link>System\Drawing\KnownColor.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup Condition="$(TargetGroup.Contains('netcoreapp')) AND '$(TargetsWindows)' == 'true'">
<!-- Windows-specific -->
<Compile Include="AssemblyRef.cs" />
<Compile Include="SRDescriptionAttribute.cs" />
Expand Down Expand Up @@ -281,7 +287,7 @@
<Link>Common\System\Runtime\InteropServices\FunctionWrapper.Windows.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp2.0' AND '$(TargetsUnix)' == 'true'">
<ItemGroup Condition="$(TargetGroup.Contains('netcoreapp')) AND '$(TargetsUnix)' == 'true'">
<!-- Unix-specific -->
<Compile Include="System\Drawing\Graphics.Unix.cs" />
<Compile Include="System\Drawing\Icon.Unix.cs" />
Expand Down Expand Up @@ -328,19 +334,32 @@
<Compile Include="$(CommonPath)\Interop\Unix\Interop.Libraries.cs">
<Link>Common\Interop\Unix\Interop.Libraries.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Unix\libdl\Interop.dlopen.cs">
<Link>Common\Interop\Unix\libdl\Interop.dlopen.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Unix\libdl\Interop.dlsym.cs">
<Link>Common\Interop\Unix\libdl\Interop.dlsym.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Runtime\InteropServices\FunctionWrapper.Unix.cs">
<Link>Common\System\Runtime\InteropServices\FunctionWrapper.Unix.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.DlOpenFlags.cs">
<Link>Common\Interop\Unix\System.Native\Interop.DlOpenFlags.cs</Link>
</Compile>
<EmbeddedResource Include="Resources\System\Drawing\Error.ico">
<LogicalName>placeholder.ico</LogicalName>
</EmbeddedResource>
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp2.0' AND '$(TargetsUnix)' == 'true'">
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.DlOpen.netcoreapp20.cs">
<Link>Common\Interop\Unix\System.Native\Interop.DlOpen.netcoreapp20.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.DlSym.netcoreapp20.cs">
<Link>Common\Interop\Unix\System.Native\Interop.DlSym.netcoreapp20.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp' AND '$(TargetsUnix)' == 'true'">
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.DlOpen.cs">
<Link>Common\Interop\Unix\System.Native\Interop.DlOpen.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.DlSym.cs">
<Link>Common\Interop\Unix\System.Native\Interop.DlSym.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' != 'netfx'">
<Reference Include="Microsoft.Win32.Primitives" />
<Reference Include="System.Collections" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,18 @@ private static IntPtr LoadNativeLibrary()
IntPtr lib = IntPtr.Zero;
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
lib = Interop.Libdl.dlopen("libgdiplus.dylib", Interop.Libdl.RTLD_NOW);
lib = Interop.Sys.DlOpen("libgdiplus.dylib", Interop.Sys.DlOpenFlags.RTLD_NOW);
}
else
{
// Various Unix package managers have chosen different names for the "libgdiplus" shared library.
// The mono project, where libgdiplus originated, allowed both of the names below to be used, via
// a global configuration setting. We prefer the "unversioned" shared object name, and fallback to
// the name suffixed with ".0".
lib = Interop.Libdl.dlopen("libgdiplus.so", Interop.Libdl.RTLD_NOW);
lib = Interop.Sys.DlOpen("libgdiplus.so", Interop.Sys.DlOpenFlags.RTLD_NOW);
if (lib == IntPtr.Zero)
{
lib = Interop.Libdl.dlopen("libgdiplus.so.0", Interop.Libdl.RTLD_NOW);
lib = Interop.Sys.DlOpen("libgdiplus.so.0", Interop.Sys.DlOpenFlags.RTLD_NOW);
}
}

Expand All @@ -44,7 +44,7 @@ private static IntPtr LoadNativeLibrary()
return lib;
}

private static IntPtr LoadFunctionPointer(IntPtr nativeLibraryHandle, string functionName) => Interop.Libdl.dlsym(nativeLibraryHandle, functionName);
private static IntPtr LoadFunctionPointer(IntPtr nativeLibraryHandle, string functionName) => Interop.Sys.DlSym(nativeLibraryHandle, functionName);

private static void PlatformInitialize()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ internal static class LibcupsNative
private static IntPtr LoadLibcups()
{
// We allow both "libcups.so" and "libcups.so.2" to be loaded.
IntPtr lib = Interop.Libdl.dlopen("libcups.so", Interop.Libdl.RTLD_NOW);
IntPtr lib = Interop.Sys.DlOpen("libcups.so", Interop.Sys.DlOpenFlags.RTLD_NOW);
if (lib == IntPtr.Zero)
{
lib = Interop.Libdl.dlopen("libcups.so.2", Interop.Libdl.RTLD_NOW);
lib = Interop.Sys.DlOpen("libcups.so.2", Interop.Sys.DlOpenFlags.RTLD_NOW);
}

return lib;
Expand Down
10 changes: 3 additions & 7 deletions src/System.Drawing.Common/tests/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ public static bool GetGdiplusIsAvailable()
IntPtr nativeLib;
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
nativeLib = dlopen("libgdiplus.dylib", RTLD_NOW);
nativeLib = Interop.Sys.DlOpen("libgdiplus.dylib", Interop.Sys.DlOpenFlags.RTLD_NOW);
}
else
{
nativeLib = dlopen("libgdiplus.so", RTLD_NOW);
nativeLib = Interop.Sys.DlOpen("libgdiplus.so", Interop.Sys.DlOpenFlags.RTLD_NOW);
if (nativeLib == IntPtr.Zero)
{
nativeLib = dlopen("libgdiplus.so.0", RTLD_NOW);
nativeLib = Interop.Sys.DlOpen("libgdiplus.so.0", Interop.Sys.DlOpenFlags.RTLD_NOW);
}
}

Expand Down Expand Up @@ -92,10 +92,6 @@ public static bool IsAnyInstalledPrinters()
return PrinterSettings.InstalledPrinters.Count > 0;
}

[DllImport("libdl")]
private static extern IntPtr dlopen(string libName, int flags);
public const int RTLD_NOW = 0x002;

public static string GetTestBitmapPath(string fileName) => GetTestPath("bitmaps", fileName);
public static string GetTestFontPath(string fileName) => GetTestPath("fonts", fileName);
public static string GetTestColorProfilePath(string fileName) => GetTestPath("colorProfiles", fileName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.DlOpen.cs">
<Link>Common\Interop\Unix\System.Native\Interop.DlOpen.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.DlOpenFlags.cs">
<Link>Common\Interop\Unix\System.Native\Interop.DlOpenFlags.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Unix\Interop.Libraries.cs">
<Link>Common\Interop\Unix\Interop.Libraries.cs</Link>
</Compile>
<Compile Include="BitmapTests.cs" />
<Compile Include="BrushTests.cs" />
<Compile Include="BrushesTests.cs" />
Expand Down