Skip to content

Commit

Permalink
Add Per-assembly Load Native Library callbacks
Browse files Browse the repository at this point in the history
This Change implements the Native Library resolution
Call-backs proposed in https://github.com/dotnet/corefx/issues/32015

public static bool RegisterDllImportResolver(
    Assembly assembly,
    Func<string, Assembly, DllImportSearchPath, IntPtr> callback
);

This API is not yet approved, and the API contracts in CoreFX
will not be added until the API approval is complete.
In the meantime, we want to have the code reviewed, tested, and
avaiable in CoreCLR.
  • Loading branch information
swaroop-sridhar authored and swaroop-sridhar committed Jan 11, 2019
1 parent 459b58a commit 09b0e78
Show file tree
Hide file tree
Showing 15 changed files with 395 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ public static partial class Marshal
internal static Guid IID_IUnknown = new Guid(0, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);
#endif //FEATURE_COMINTEROP

static Marshal()
{
nativeDllResolveMap = new ConditionalWeakTable<Assembly, Func<string, Assembly, DllImportSearchPath?, IntPtr>>();
}

private const int LMEM_FIXED = 0;
private const int LMEM_MOVEABLE = 2;
#if !FEATURE_PAL
Expand Down
1 change: 1 addition & 0 deletions src/vm/callhelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,7 @@ enum DispatchCallSimpleFlags
#define STRINGREF_TO_ARGHOLDER(x) (LPVOID)STRINGREFToObject(x)
#define PTR_TO_ARGHOLDER(x) (LPVOID)x
#define DWORD_TO_ARGHOLDER(x) (LPVOID)(SIZE_T)x
#define BOOL_TO_ARGHOLDER(x) DWORD_TO_ARGHOLDER(x)

#define INIT_VARIABLES(count) \
DWORD __numArgs = count; \
Expand Down
124 changes: 96 additions & 28 deletions src/vm/dllimport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6144,7 +6144,7 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryFromPath(LPCWSTR libraryPath, BOOL thr

// static
NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryByName(LPCWSTR libraryName, Assembly *callingAssembly,
BOOL hasDllImportSearchFlag, DWORD dllImportSearchFlag,
BOOL hasDllImportSearchFlags, DWORD dllImportSearchFlags,
BOOL throwOnError)
{
CONTRACTL
Expand All @@ -6157,15 +6157,15 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryByName(LPCWSTR libraryName, Assembly *

LoadLibErrorTracker errorTracker;

// First checks if a default DllImportSearchPathFlag was passed in, if so, use that value.
// First checks if a default dllImportSearchPathFlags was passed in, if so, use that value.
// Otherwise checks if the assembly has the DefaultDllImportSearchPathsAttribute attribute. If so, use that value.
BOOL searchAssemblyDirectory = TRUE;
DWORD dllImportSearchPathFlag = 0;
DWORD dllImportSearchPathFlags = 0;

if (hasDllImportSearchFlag)
if (hasDllImportSearchFlags)
{
dllImportSearchPathFlag = dllImportSearchFlag & ~DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY;
searchAssemblyDirectory = dllImportSearchFlag & DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY;
dllImportSearchPathFlags = dllImportSearchFlags & ~DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY;
searchAssemblyDirectory = dllImportSearchFlags & DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY;

}
else
Expand All @@ -6174,13 +6174,13 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryByName(LPCWSTR libraryName, Assembly *

if (pModule->HasDefaultDllImportSearchPathsAttribute())
{
dllImportSearchPathFlag = pModule->DefaultDllImportSearchPathsAttributeCachedValue();
dllImportSearchPathFlags = pModule->DefaultDllImportSearchPathsAttributeCachedValue();
searchAssemblyDirectory = pModule->DllImportSearchAssemblyDirectory();
}
}

NATIVE_LIBRARY_HANDLE hmod =
LoadLibraryModuleBySearch(callingAssembly, searchAssemblyDirectory, dllImportSearchPathFlag, &errorTracker, libraryName);
LoadLibraryModuleBySearch(callingAssembly, searchAssemblyDirectory, dllImportSearchPathFlags, &errorTracker, libraryName);

if (throwOnError && (hmod == nullptr))
{
Expand All @@ -6199,11 +6199,11 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(NDirectMethodDesc * pMD
// First checks if the method has DefaultDllImportSearchPathsAttribute. If so, use that value.
// Otherwise checks if the assembly has the attribute. If so, use that value.
BOOL searchAssemblyDirectory = TRUE;
DWORD dllImportSearchPathFlag = 0;
DWORD dllImportSearchPathFlags = 0;

if (pMD->HasDefaultDllImportSearchPathsAttribute())
{
dllImportSearchPathFlag = pMD->DefaultDllImportSearchPathsAttributeCachedValue();
dllImportSearchPathFlags = pMD->DefaultDllImportSearchPathsAttributeCachedValue();
searchAssemblyDirectory = pMD->DllImportSearchAssemblyDirectory();
}
else
Expand All @@ -6212,13 +6212,13 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(NDirectMethodDesc * pMD

if (pModule->HasDefaultDllImportSearchPathsAttribute())
{
dllImportSearchPathFlag = pModule->DefaultDllImportSearchPathsAttributeCachedValue();
dllImportSearchPathFlags = pModule->DefaultDllImportSearchPathsAttributeCachedValue();
searchAssemblyDirectory = pModule->DllImportSearchAssemblyDirectory();
}
}

Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();
return LoadLibraryModuleBySearch(pAssembly, searchAssemblyDirectory, dllImportSearchPathFlag, pErrorTracker, wszLibName);
return LoadLibraryModuleBySearch(pAssembly, searchAssemblyDirectory, dllImportSearchPathFlags, pErrorTracker, wszLibName);
}

// static
Expand Down Expand Up @@ -6267,23 +6267,32 @@ INT_PTR NDirect::GetNativeLibraryExport(NATIVE_LIBRARY_HANDLE handle, LPCWSTR sy
return address;
}

#ifndef PLATFORM_UNIX
BOOL IsWindowsAPI(PCWSTR wszLibName)
{
// This is replicating quick check from the OS implementation of api sets.
return SString::_wcsnicmp(wszLibName, W("api-"), 4) == 0 ||
SString::_wcsnicmp(wszLibName, W("ext-"), 4) == 0;
}
#endif // !PLATFORM_UNIX

// static
NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, AppDomain* pDomain, PCWSTR wszLibName)
NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, PCWSTR wszLibName)
{
STANDARD_VM_CONTRACT;
//Dynamic Pinvoke Support:
//Check if we need to provide the host a chance to provide the unmanaged dll

#ifndef PLATFORM_UNIX
// Prevent Overriding of Windows API sets.
// This is replicating quick check from the OS implementation of api sets.
if (SString::_wcsnicmp(wszLibName, W("api-"), 4) == 0 || SString::_wcsnicmp(wszLibName, W("ext-"), 4) == 0)
if (IsWindowsAPI(wszLibName))
{
// Prevent Overriding of Windows API sets.
return NULL;
}
#endif
#endif // !PLATFORM_UNIX

LPVOID hmod = NULL;
AppDomain* pDomain = GetAppDomain();
CLRPrivBinderCoreCLR *pTPABinder = pDomain->GetTPABinderContext();
Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();

Expand Down Expand Up @@ -6349,6 +6358,55 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaHost(NDirectMethodDesc * pMD,
return (NATIVE_LIBRARY_HANDLE)hmod;
}

NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaCallBack(NDirectMethodDesc * pMD, LPCWSTR wszLibName)
{
#ifndef PLATFORM_UNIX
if (IsWindowsAPI(wszLibName))
{
// Prevent Overriding of Windows API sets.
return NULL;
}
#endif // !PLATFORM_UNIX

DWORD dllImportSearchPathFlags = 0;
BOOL hasDllImportSearchPathFlags = pMD->HasDefaultDllImportSearchPathsAttribute();
if (hasDllImportSearchPathFlags)
{
dllImportSearchPathFlags = pMD->DefaultDllImportSearchPathsAttributeCachedValue();
if (pMD->DllImportSearchAssemblyDirectory())
dllImportSearchPathFlags |= DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY;
}

GCX_COOP();

struct {
STRINGREF libNameRef;
OBJECTREF assemblyRef;
} protect;


Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();
protect.libNameRef = StringObject::NewString(wszLibName);
protect.assemblyRef = pAssembly->GetExposedObject();

NATIVE_LIBRARY_HANDLE handle = NULL;

GCPROTECT_BEGIN(protect);

PREPARE_NONVIRTUAL_CALLSITE(METHOD__MARSHAL__LOADLIBRARYCALLBACKSTUB);
DECLARE_ARGHOLDER_ARRAY(args, 4);
args[ARGNUM_0] = STRINGREF_TO_ARGHOLDER(protect.libNameRef);
args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(protect.assemblyRef);
args[ARGNUM_2] = BOOL_TO_ARGHOLDER(hasDllImportSearchPathFlags);
args[ARGNUM_3] = DWORD_TO_ARGHOLDER(dllImportSearchPathFlags);

// Make the call
CALL_MANAGED_METHOD(handle, NATIVE_LIBRARY_HANDLE, args);
GCPROTECT_END();

return handle;
}

// Try to load the module alongside the assembly where the PInvoke was declared.
NATIVE_LIBRARY_HANDLE NDirect::LoadFromPInvokeAssemblyDirectory(Assembly *pAssembly, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker)
{
Expand All @@ -6372,11 +6430,12 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadFromPInvokeAssemblyDirectory(Assembly *pAssem
}

// Try to load the module from the native DLL search directories
NATIVE_LIBRARY_HANDLE NDirect::LoadFromNativeDllSearchDirectories(AppDomain* pDomain, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker)
NATIVE_LIBRARY_HANDLE NDirect::LoadFromNativeDllSearchDirectories(LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker)
{
STANDARD_VM_CONTRACT;

NATIVE_LIBRARY_HANDLE hmod = NULL;
AppDomain* pDomain = GetAppDomain();

if (pDomain->HasNativeDllSearchDirectories())
{
Expand Down Expand Up @@ -6498,7 +6557,7 @@ static void DetermineLibNameVariations(const WCHAR** libNameVariations, int* num
// Search for the library and variants of its name in probing directories.
//static
NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(Assembly *callingAssembly,
BOOL searchAssemblyDirectory, DWORD dllImportSearchPathFlag,
BOOL searchAssemblyDirectory, DWORD dllImportSearchPathFlags,
LoadLibErrorTracker * pErrorTracker, LPCWSTR wszLibName)
{
STANDARD_VM_CONTRACT;
Expand All @@ -6508,7 +6567,7 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(Assembly *callingAssemb
#if defined(FEATURE_CORESYSTEM) && !defined(PLATFORM_UNIX)
// Try to go straight to System32 for Windows API sets. This is replicating quick check from
// the OS implementation of api sets.
if (SString::_wcsnicmp(wszLibName, W("api-"), 4) == 0 || SString::_wcsnicmp(wszLibName, W("ext-"), 4) == 0)
if (IsWindowsAPI(wszLibName))
{
hmod = LocalLoadLibraryHelper(wszLibName, LOAD_LIBRARY_SEARCH_SYSTEM32, pErrorTracker);
if (hmod != NULL)
Expand Down Expand Up @@ -6536,7 +6595,7 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(Assembly *callingAssemb
currLibNameVariation.Printf(prefixSuffixCombinations[i], PLATFORM_SHARED_LIB_PREFIX_W, wszLibName, PLATFORM_SHARED_LIB_SUFFIX_W);

// NATIVE_DLL_SEARCH_DIRECTORIES set by host is considered well known path
hmod = LoadFromNativeDllSearchDirectories(pDomain, currLibNameVariation, loadWithAlteredPathFlags, pErrorTracker);
hmod = LoadFromNativeDllSearchDirectories(currLibNameVariation, loadWithAlteredPathFlags, pErrorTracker);
if (hmod != NULL)
{
return hmod;
Expand All @@ -6545,11 +6604,11 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(Assembly *callingAssemb
if (!libNameIsRelativePath)
{
DWORD flags = loadWithAlteredPathFlags;
if ((dllImportSearchPathFlag & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR) != 0)
if ((dllImportSearchPathFlags & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR) != 0)
{
// LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR is the only flag affecting absolute path. Don't OR the flags
// unconditionally as all absolute path P/Invokes could then lose LOAD_WITH_ALTERED_SEARCH_PATH.
flags |= dllImportSearchPathFlag;
flags |= dllImportSearchPathFlags;
}

hmod = LocalLoadLibraryHelper(currLibNameVariation, flags, pErrorTracker);
Expand All @@ -6560,14 +6619,14 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(Assembly *callingAssemb
}
else if ((callingAssembly != nullptr) && searchAssemblyDirectory)
{
hmod = LoadFromPInvokeAssemblyDirectory(callingAssembly, currLibNameVariation, loadWithAlteredPathFlags | dllImportSearchPathFlag, pErrorTracker);
hmod = LoadFromPInvokeAssemblyDirectory(callingAssembly, currLibNameVariation, loadWithAlteredPathFlags | dllImportSearchPathFlags, pErrorTracker);
if (hmod != NULL)
{
return hmod;
}
}

hmod = LocalLoadLibraryHelper(currLibNameVariation, dllImportSearchPathFlag, pErrorTracker);
hmod = LocalLoadLibraryHelper(currLibNameVariation, dllImportSearchPathFlags, pErrorTracker);
if (hmod != NULL)
{
return hmod;
Expand Down Expand Up @@ -6597,7 +6656,7 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(Assembly *callingAssemb
Assembly *pAssembly = spec.LoadAssembly(FILE_LOADED);
Module *pModule = pAssembly->FindModuleByName(szLibName);

hmod = LocalLoadLibraryHelper(pModule->GetPath(), loadWithAlteredPathFlags | dllImportSearchPathFlag, pErrorTracker);
hmod = LocalLoadLibraryHelper(pModule->GetPath(), loadWithAlteredPathFlags | dllImportSearchPathFlags, pErrorTracker);
}
}

Expand All @@ -6618,19 +6677,28 @@ HINSTANCE NDirect::LoadLibraryModule(NDirectMethodDesc * pMD, LoadLibErrorTracke
if ( !name || !*name )
return NULL;

ModuleHandleHolder hmod;

PREFIX_ASSUME( name != NULL );
MAKE_WIDEPTR_FROMUTF8( wszLibName, name );

ModuleHandleHolder hmod = LoadLibraryModuleViaCallBack(pMD, wszLibName);
if (hmod != NULL)
{
#ifdef FEATURE_PAL
// Register the system library handle with PAL and get a PAL library handle
hmod = PAL_RegisterLibraryDirect(hmod, wszLibName);
#endif // FEATURE_PAL
return hmod.Extract();
}

AppDomain* pDomain = GetAppDomain();

// AssemblyLoadContext is not supported in AppX mode and thus,
// we should not perform PInvoke resolution via it when operating in
// AppX mode.
if (!AppX::IsAppXProcess())
{
hmod = LoadLibraryModuleViaHost(pMD, pDomain, wszLibName);
hmod = LoadLibraryModuleViaHost(pMD, wszLibName);
if (hmod != NULL)
{
#ifdef FEATURE_PAL
Expand Down
9 changes: 5 additions & 4 deletions src/vm/dllimport.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class NDirect
static LPVOID NDirectGetEntryPoint(NDirectMethodDesc *pMD, HINSTANCE hMod);
static NATIVE_LIBRARY_HANDLE LoadLibraryFromPath(LPCWSTR libraryPath, BOOL throwOnError);
static NATIVE_LIBRARY_HANDLE LoadLibraryByName(LPCWSTR name, Assembly *callingAssembly,
BOOL hasDllImportSearchPathFlag, DWORD dllImportSearchPathFlag,
BOOL hasDllImportSearchPathFlags, DWORD dllImportSearchPathFlags,
BOOL throwOnError);
static HINSTANCE LoadLibraryModule(NDirectMethodDesc * pMD, LoadLibErrorTracker *pErrorTracker);
static void FreeNativeLibrary(NATIVE_LIBRARY_HANDLE handle);
Expand Down Expand Up @@ -122,11 +122,12 @@ class NDirect
private:
NDirect() {LIMITED_METHOD_CONTRACT;}; // prevent "new"'s on this class

static NATIVE_LIBRARY_HANDLE LoadFromNativeDllSearchDirectories(AppDomain* pDomain, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker);
static NATIVE_LIBRARY_HANDLE LoadFromNativeDllSearchDirectories(LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker);
static NATIVE_LIBRARY_HANDLE LoadFromPInvokeAssemblyDirectory(Assembly *pAssembly, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker);
static NATIVE_LIBRARY_HANDLE LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, AppDomain* pDomain, const wchar_t* wszLibName);
static NATIVE_LIBRARY_HANDLE LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, const wchar_t* wszLibName);
static NATIVE_LIBRARY_HANDLE LoadLibraryModuleViaCallBack(NDirectMethodDesc * pMD, const wchar_t* wszLibName);
static NATIVE_LIBRARY_HANDLE LoadLibraryModuleBySearch(NDirectMethodDesc * pMD, LoadLibErrorTracker * pErrorTracker, const wchar_t* wszLibName);
static NATIVE_LIBRARY_HANDLE LoadLibraryModuleBySearch(Assembly *callingAssembly, BOOL searchAssemblyDirectory, DWORD dllImportSearchPathFlag, LoadLibErrorTracker * pErrorTracker, const wchar_t* wszLibName);
static NATIVE_LIBRARY_HANDLE LoadLibraryModuleBySearch(Assembly *callingAssembly, BOOL searchAssemblyDirectory, DWORD dllImportSearchPathFlags, LoadLibErrorTracker * pErrorTracker, const wchar_t* wszLibName);

#if !defined(FEATURE_PAL)
// Indicates if the OS supports the new secure LoadLibraryEx flags introduced in KB2533623
Expand Down
6 changes: 3 additions & 3 deletions src/vm/interoputil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -898,8 +898,8 @@ void FillExceptionData(

//---------------------------------------------------------------------------
//returns true if pImport has DefaultDllImportSearchPathsAttribute
//if true, also returns dllImportSearchPathFlag and searchAssemblyDirectory values.
BOOL GetDefaultDllImportSearchPathsAttributeValue(IMDInternalImport *pImport, mdToken token, DWORD * pDllImportSearchPathFlag)
//if true, also returns dllImportSearchPathFlags and searchAssemblyDirectory values.
BOOL GetDefaultDllImportSearchPathsAttributeValue(IMDInternalImport *pImport, mdToken token, DWORD * pDllImportSearchPathFlags)
{
CONTRACTL
{
Expand Down Expand Up @@ -929,7 +929,7 @@ BOOL GetDefaultDllImportSearchPathsAttributeValue(IMDInternalImport *pImport, md
args[0].InitEnum(SERIALIZATION_TYPE_U4, (ULONG)0);

ParseKnownCaArgs(ca, args, lengthof(args));
*pDllImportSearchPathFlag = args[0].val.u4;
*pDllImportSearchPathFlags = args[0].val.u4;
return TRUE;
}

Expand Down
2 changes: 1 addition & 1 deletion src/vm/interoputil.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ void FillExceptionData(

//---------------------------------------------------------------------------
//returns true if pImport has DefaultDllImportSearchPathsAttribute
//if true, also returns dllImportSearchPathFlag and searchAssemblyDirectory values.
//if true, also returns dllImportSearchPathFlags and searchAssemblyDirectory values.
BOOL GetDefaultDllImportSearchPathsAttributeValue(IMDInternalImport *pImport, mdToken token, DWORD * pDlImportSearchPathFlag);

//---------------------------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions src/vm/metasig.h
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,7 @@ DEFINE_METASIG_T(IM(RefGuid_OutIntPtr_RetCustomQueryInterfaceResult, r(g(GUID))
#endif //FEATURE_COMINTEROP

DEFINE_METASIG_T(SM(IntPtr_AssemblyName_RetAssemblyBase, I C(ASSEMBLY_NAME), C(ASSEMBLYBASE)))
DEFINE_METASIG_T(SM(Str_AssemblyBase_Bool_UInt_RetIntPtr, s C(ASSEMBLYBASE) F K, I))

// ThreadPool
DEFINE_METASIG(SM(Obj_Bool_RetVoid, j F, v))
Expand Down
2 changes: 1 addition & 1 deletion src/vm/mscorlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ DEFINE_METHOD(MARSHAL, GET_FUNCTION_POINTER_FOR_DELEGATE, GetFuncti
DEFINE_METHOD(MARSHAL, GET_DELEGATE_FOR_FUNCTION_POINTER, GetDelegateForFunctionPointer, SM_IntPtr_Type_RetDelegate)
DEFINE_METHOD(MARSHAL, ALLOC_CO_TASK_MEM, AllocCoTaskMem, SM_Int_RetIntPtr)
DEFINE_FIELD(MARSHAL, SYSTEM_MAX_DBCS_CHAR_SIZE, SystemMaxDBCSCharSize)

DEFINE_METHOD(MARSHAL, LOADLIBRARYCALLBACKSTUB, LoadLibraryCallbackStub, SM_Str_AssemblyBase_Bool_UInt_RetIntPtr)

DEFINE_CLASS(MEMBER, Reflection, MemberInfo)

Expand Down
13 changes: 13 additions & 0 deletions tests/src/Interop/MarshalAPI/DllImportUtil/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
cmake_minimum_required (VERSION 2.6)
project (NativeLib)
include_directories(${INC_PLATFORM_DIR})
set(SOURCES NativeLibrary.cpp)

# add the executable
add_library (NativeLib SHARED ${SOURCES})
target_link_libraries(NativeLib ${LINK_LIBRARIES_ADDITIONAL})

# add the install targets
install (TARGETS NativeLib DESTINATION bin)


Loading

0 comments on commit 09b0e78

Please sign in to comment.