未验证 提交 3c126e6e 编写于 作者: J Jeremy Koritzinsky 提交者: GitHub

Change CoreCLR diagnostic resource production to remove cross-component build dependency (#67018)

上级 96d1df6d
...@@ -528,13 +528,9 @@ if %__BuildNative% EQU 1 ( ...@@ -528,13 +528,9 @@ if %__BuildNative% EQU 1 (
if /i "%__BuildArch%" == "x86" ( set __VCBuildArch=x86 ) if /i "%__BuildArch%" == "x86" ( set __VCBuildArch=x86 )
if /i "%__BuildArch%" == "arm" ( if /i "%__BuildArch%" == "arm" (
set __VCBuildArch=x86_arm set __VCBuildArch=x86_arm
set ___CrossBuildDefine="-DCLR_CMAKE_CROSS_ARCH=1" "-DCLR_CMAKE_CROSS_HOST_ARCH=%__CrossArch%"
) )
if /i "%__BuildArch%" == "arm64" ( if /i "%__BuildArch%" == "arm64" (
set __VCBuildArch=x86_arm64 set __VCBuildArch=x86_arm64
if defined __CrossArch (
set ___CrossBuildDefine="-DCLR_CMAKE_CROSS_ARCH=1" "-DCLR_CMAKE_CROSS_HOST_ARCH=%__CrossArch%"
)
) )
echo %__MsgPrefix%Using environment: "%__VCToolsRoot%\vcvarsall.bat" !__VCBuildArch! echo %__MsgPrefix%Using environment: "%__VCToolsRoot%\vcvarsall.bat" !__VCBuildArch!
...@@ -549,7 +545,7 @@ if %__BuildNative% EQU 1 ( ...@@ -549,7 +545,7 @@ if %__BuildNative% EQU 1 (
set __ExtraCmakeArgs="-DCMAKE_BUILD_TYPE=!__BuildType!" set __ExtraCmakeArgs="-DCMAKE_BUILD_TYPE=!__BuildType!"
) )
set __ExtraCmakeArgs=!__ExtraCmakeArgs! !___CrossBuildDefine! "-DCLR_CMAKE_PGO_INSTRUMENT=%__PgoInstrument%" "-DCLR_CMAKE_OPTDATA_PATH=%__PgoOptDataPath%" "-DCLR_CMAKE_PGO_OPTIMIZE=%__PgoOptimize%" %__CMakeArgs% set __ExtraCmakeArgs=!__ExtraCmakeArgs! "-DCLR_CMAKE_PGO_INSTRUMENT=%__PgoInstrument%" "-DCLR_CMAKE_OPTDATA_PATH=%__PgoOptDataPath%" "-DCLR_CMAKE_PGO_OPTIMIZE=%__PgoOptimize%" %__CMakeArgs%
call "%__RepoRootDir%\eng\native\gen-buildsys.cmd" "%__ProjectDir%" "%__IntermediatesDir%" %__VSVersion% %__BuildArch% !__ExtraCmakeArgs! call "%__RepoRootDir%\eng\native\gen-buildsys.cmd" "%__ProjectDir%" "%__IntermediatesDir%" %__VSVersion% %__BuildArch% !__ExtraCmakeArgs!
if not !errorlevel! == 0 ( if not !errorlevel! == 0 (
echo %__ErrMsgPrefix%%__MsgPrefix%Error: failed to generate native component build project! echo %__ErrMsgPrefix%%__MsgPrefix%Error: failed to generate native component build project!
......
...@@ -42,7 +42,3 @@ if(NOT CLR_CMAKE_HOST_LINUX AND NOT CLR_CMAKE_HOST_OSX AND NOT FEATURE_CROSSBITN ...@@ -42,7 +42,3 @@ if(NOT CLR_CMAKE_HOST_LINUX AND NOT CLR_CMAKE_HOST_OSX AND NOT FEATURE_CROSSBITN
COMPONENT crosscomponents COMPONENT crosscomponents
) )
endif() endif()
if (CLR_CMAKE_TARGET_WIN32 AND NOT CLR_CMAKE_CROSS_ARCH)
add_dependencies(crosscomponents InjectResource GenClrDebugResource)
endif()
...@@ -29,8 +29,8 @@ function(generate_module_index Target ModuleIndexFile) ...@@ -29,8 +29,8 @@ function(generate_module_index Target ModuleIndexFile)
target_sources(runtimeinfo PRIVATE ${ModuleIndexFile}) target_sources(runtimeinfo PRIVATE ${ModuleIndexFile})
endfunction(generate_module_index) endfunction(generate_module_index)
generate_module_index(coreclr ${CMAKE_CURRENT_BINARY_DIR}/runtimemoduleindex.h)
if(NOT DEFINED CLR_CROSS_COMPONENTS_BUILD) if(NOT DEFINED CLR_CROSS_COMPONENTS_BUILD)
generate_module_index(coreclr ${CMAKE_CURRENT_BINARY_DIR}/runtimemoduleindex.h)
add_dependencies(runtimeinfo inject_debug_resources_coreclr) add_dependencies(runtimeinfo inject_debug_resources_coreclr)
generate_module_index(mscordaccore ${CMAKE_CURRENT_BINARY_DIR}/dacmoduleindex.h) generate_module_index(mscordaccore ${CMAKE_CURRENT_BINARY_DIR}/dacmoduleindex.h)
generate_module_index(mscordbi ${CMAKE_CURRENT_BINARY_DIR}/dbimoduleindex.h) generate_module_index(mscordbi ${CMAKE_CURRENT_BINARY_DIR}/dbimoduleindex.h)
......
...@@ -2,10 +2,10 @@ if(CLR_CMAKE_TARGET_WIN32) ...@@ -2,10 +2,10 @@ if(CLR_CMAKE_TARGET_WIN32)
add_subdirectory(clretwrc) add_subdirectory(clretwrc)
endif(CLR_CMAKE_TARGET_WIN32) endif(CLR_CMAKE_TARGET_WIN32)
add_subdirectory(dbgshim) add_subdirectory(dbgshim)
if (NOT (CLR_CMAKE_TARGET_WIN32 AND (CLR_CMAKE_TARGET_ARCH_I386 OR CLR_CMAKE_TARGET_ARCH_ARM) AND CLR_CMAKE_HOST_ARCH_AMD64)) if (NOT (CLR_CMAKE_TARGET_WIN32 AND FEATURE_CROSSBITNESS))
add_subdirectory(mscordbi) add_subdirectory(mscordbi)
add_subdirectory(mscordac) add_subdirectory(mscordac)
add_subdirectory(mscoree)
endif() endif()
add_subdirectory(mscoree)
add_subdirectory(mscorpe) add_subdirectory(mscorpe)
add_subdirectory(mscorrc) add_subdirectory(mscorrc)
...@@ -173,6 +173,26 @@ target_link_libraries(coreclr_static PUBLIC ${CORECLR_LIBRARIES} clrjit_static c ...@@ -173,6 +173,26 @@ target_link_libraries(coreclr_static PUBLIC ${CORECLR_LIBRARIES} clrjit_static c
target_compile_definitions(coreclr_static PUBLIC CORECLR_EMBEDDED) target_compile_definitions(coreclr_static PUBLIC CORECLR_EMBEDDED)
if(CLR_CMAKE_TARGET_WIN32) if(CLR_CMAKE_TARGET_WIN32)
set(CLRDEBUGINFO_RESOURCE_PATH ${CMAKE_CURRENT_BINARY_DIR}/clr_debug_resource.bin)
add_custom_target(
clr_debug_resources
DEPENDS mscordaccore mscordbi
# make CLRDEBUGINFO resource
COMMAND powershell -NoProfile -ExecutionPolicy ByPass -File "${CMAKE_CURRENT_SOURCE_DIR}/GenClrDebugResource.ps1" -dac $<TARGET_FILE:mscordaccore> -dbi $<TARGET_FILE:mscordbi> -out ${CLRDEBUGINFO_RESOURCE_PATH}
)
configure_file(dump_helper_resource.rc.in ${CMAKE_CURRENT_BINARY_DIR}/dump_helper_resource.rc)
set(EMBEDDED_MINIDUMP_AUXILIARY_PROVIDER ON)
configure_file(dump_helper_resource.rc.in ${CMAKE_CURRENT_BINARY_DIR}/dump_helper_resource_embedded_minidump_provider.rc)
target_sources(coreclr PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/dump_helper_resource.rc)
target_sources(coreclr_static PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/dump_helper_resource_embedded_minidump_provider.rc)
add_dependencies(coreclr clr_debug_resources)
add_dependencies(coreclr_static clr_debug_resources)
# Add dac table & debug resource to coreclr # Add dac table & debug resource to coreclr
get_include_directories(INC_DIR) get_include_directories(INC_DIR)
get_compile_definitions(PREPROCESS_DEFINITIONS) get_compile_definitions(PREPROCESS_DEFINITIONS)
...@@ -191,10 +211,9 @@ if(CLR_CMAKE_TARGET_WIN32) ...@@ -191,10 +211,9 @@ if(CLR_CMAKE_TARGET_WIN32)
clr_unknown_arch() clr_unknown_arch()
endif() endif()
# dacess.h defines this constant
if (CLR_CMAKE_CROSS_ARCH) # The value is a constract between the DAC and the runtime
include(${CMAKE_INSTALL_PREFIX}/${CLR_CMAKE_CROSS_HOST_ARCH}/dactabletools/dactabletools.cmake) set (DACCESS_TABLE_RESOURCE COREXTERNALDATAACCESSRESOURCE)
endif()
add_custom_command( add_custom_command(
DEPENDS coreclr mscordaccore mscordbi ${CLR_DIR}/debug/daccess/daccess.cpp DEPENDS coreclr mscordaccore mscordbi ${CLR_DIR}/debug/daccess/daccess.cpp
...@@ -203,17 +222,10 @@ if(CLR_CMAKE_TARGET_WIN32) ...@@ -203,17 +222,10 @@ if(CLR_CMAKE_TARGET_WIN32)
# make and inject dactable for coreclr # make and inject dactable for coreclr
COMMAND cmd /c ${CLR_REPO_ROOT_DIR}/dotnet.cmd exec ${CMAKE_INSTALL_PREFIX}/DacTableGen/DacTableGen.dll /dac:${CMAKE_CURRENT_BINARY_DIR}/daccess.i /pdb:$<TARGET_PDB_FILE:coreclr> /dll:$<TARGET_FILE:coreclr> /bin:${CMAKE_CURRENT_BINARY_DIR}/wks.bin COMMAND cmd /c ${CLR_REPO_ROOT_DIR}/dotnet.cmd exec ${CMAKE_INSTALL_PREFIX}/DacTableGen/DacTableGen.dll /dac:${CMAKE_CURRENT_BINARY_DIR}/daccess.i /pdb:$<TARGET_PDB_FILE:coreclr> /dll:$<TARGET_FILE:coreclr> /bin:${CMAKE_CURRENT_BINARY_DIR}/wks.bin
COMMAND InjectResource /bin:${CMAKE_CURRENT_BINARY_DIR}/wks.bin /dll:$<TARGET_FILE:coreclr> COMMAND cmd /c ${CLR_REPO_ROOT_DIR}/dotnet.cmd exec ${CMAKE_INSTALL_PREFIX}/InjectResource/InjectResource.dll --bin ${CMAKE_CURRENT_BINARY_DIR}/wks.bin --image $<TARGET_FILE:coreclr> --name ${DACCESS_TABLE_RESOURCE}
# make CLRDEBUGINFO resource and inject into coreclr
COMMAND GenClrDebugResource /dac:$<TARGET_FILE:mscordaccore> /dbi:$<TARGET_FILE:mscordbi> /sku:onecoreclr /out:${CMAKE_CURRENT_BINARY_DIR}/clrDebugResource.bin
COMMAND InjectResource /bin:${CMAKE_CURRENT_BINARY_DIR}/clrDebugResource.bin /dll:$<TARGET_FILE:coreclr> /name:CLRDEBUGINFO
# inject MINIDUMP_AUXILIARY_PROVIDER into coreclr
COMMAND InjectResource /bin:${CMAKE_CURRENT_SOURCE_DIR}/dump_helper_resource.bin /dll:$<TARGET_FILE:coreclr> /name:MINIDUMP_AUXILIARY_PROVIDER
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/inject_debug_resources_coreclr.timestamp COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/inject_debug_resources_coreclr.timestamp
COMMENT Add dactable, debug resources, and dump helper resources to coreclr COMMENT Add dactable to coreclr
) )
if(NOT DEFINED CLR_CROSS_COMPONENTS_BUILD) if(NOT DEFINED CLR_CROSS_COMPONENTS_BUILD)
...@@ -228,14 +240,10 @@ if(CLR_CMAKE_TARGET_WIN32) ...@@ -228,14 +240,10 @@ if(CLR_CMAKE_TARGET_WIN32)
# make and inject dactable for singlefilehost # make and inject dactable for singlefilehost
COMMAND cmd /c ${CLR_REPO_ROOT_DIR}/dotnet.cmd exec ${CMAKE_INSTALL_PREFIX}/DacTableGen/DacTableGen.dll /dac:${CMAKE_CURRENT_BINARY_DIR}/daccess.i /pdb:$<TARGET_PDB_FILE:singlefilehost> /dll:$<TARGET_FILE:singlefilehost> /bin:${CMAKE_CURRENT_BINARY_DIR}/sfh.bin COMMAND cmd /c ${CLR_REPO_ROOT_DIR}/dotnet.cmd exec ${CMAKE_INSTALL_PREFIX}/DacTableGen/DacTableGen.dll /dac:${CMAKE_CURRENT_BINARY_DIR}/daccess.i /pdb:$<TARGET_PDB_FILE:singlefilehost> /dll:$<TARGET_FILE:singlefilehost> /bin:${CMAKE_CURRENT_BINARY_DIR}/sfh.bin
COMMAND InjectResource /bin:${CMAKE_CURRENT_BINARY_DIR}/sfh.bin /dll:$<TARGET_FILE:singlefilehost> COMMAND cmd /c ${CLR_REPO_ROOT_DIR}/dotnet.cmd exec ${CMAKE_INSTALL_PREFIX}/InjectResource/InjectResource.dll --bin ${CMAKE_CURRENT_BINARY_DIR}/sfh.bin --image $<TARGET_FILE:singlefilehost> --name ${DACCESS_TABLE_RESOURCE}
# make CLRDEBUGINFO resource and inject into singlefilehost
COMMAND GenClrDebugResource /dac:$<TARGET_FILE:mscordaccore> /dbi:$<TARGET_FILE:mscordbi> /sku:onecoreclr /out:${CMAKE_CURRENT_BINARY_DIR}/clrDebugResource.bin
COMMAND InjectResource /bin:${CMAKE_CURRENT_BINARY_DIR}/clrDebugResource.bin /dll:$<TARGET_FILE:singlefilehost> /name:CLRDEBUGINFO
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/inject_debug_resources_singlefilehost.timestamp COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/inject_debug_resources_singlefilehost.timestamp
COMMENT Add dactable, debug resources, and dump helper resources to singlefilehost COMMENT Add dactable to singlefilehost
) )
if(NOT DEFINED CLR_CROSS_COMPONENTS_BUILD) if(NOT DEFINED CLR_CROSS_COMPONENTS_BUILD)
......
param (
[string]
$dac,
[string]
$dbi,
[string]
$out
)
function Parse-Int {
param (
[parameter(Mandatory = $true, ValueFromPipeline = $true)]
[string]$hexValue
)
return [System.Int32]::Parse($hexValue, [System.Globalization.NumberStyles]::HexNumber)
}
$clrDebugResource = [System.IO.BinaryWriter]::new([System.IO.File]::OpenWrite($out))
try {
# We're creating the resource with the following layout (represented as a C struct)
# struct CLR_DEBUG_RESOURCE
# {
# int version;
# GUID clrSkuGuid;
# int dacTimeStamp;
# int dacImageSize;
# int dbiTimeStamp;
# int dacImageSize;
# };
# Write the debug resource version
$clrDebugResource.Write(0);
# Write the GUID for CoreCLR (should match the CLR_ID_ONECORE_CLR GUID in clrinternal.idl)
$clrDebugResource.Write([System.Guid]::Parse("{0xb1ee760d,0x6c4a,0x4533,{0xba,0x41,0x6f,0x4f,0x66,0x1f,0xab,0xaf}}").ToByteArray())
[int]$dacTimeStamp = dumpbin $dac /HEADERS | Select-String "([0-9A-Fa-f]+) time date stamp" | %{ $_.Matches.Groups[1].Value } | Parse-Int
[int]$dacImageSize = dumpbin $dac /HEADERS | Select-String "([0-9A-Fa-f]+) size of image" | %{ $_.Matches.Groups[1].Value } | Parse-Int
[int]$dbiTimeStamp = dumpbin $dbi /HEADERS | Select-String "([0-9A-Fa-f]+) time date stamp" | %{ $_.Matches.Groups[1].Value } | Parse-Int
[int]$dbiImageSize = dumpbin $dbi /HEADERS | Select-String "([0-9A-Fa-f]+) size of image" | %{ $_.Matches.Groups[1].Value } | Parse-Int
$clrDebugResource.Write($dacTimeStamp)
$clrDebugResource.Write($dacImageSize)
$clrDebugResource.Write($dbiTimeStamp)
$clrDebugResource.Write($dbiImageSize)
}
finally {
$clrDebugResource.Dispose()
}
\ No newline at end of file
dump\_helper\_resource.bin in this folder is a text file with a single 0 byte appended on the end using a hex-editor. It is unlikely it will need to be modified frequently if at all, dump\_helper\_resource.rc is used to populate the MINIDUMP\_AUXILIARY\_PROVIDER resource inside coreclr.dll on Windows. When an application crashes, Windows MinidumpWriteDump is planning to scan
but if that changes we can always create a little nicer tooling for it.
dump\_helper\_resource.bin is used to populate the DUMP\_HELPER resource inside coreclr.dll on Windows. When an application crashes, Windows MinidumpWriteDump is planning to scan
modules looking for this resource. The content of the resource is expected to be the name of a dll in the same folder, encoded in UTF8, null terminated, that implements the modules looking for this resource. The content of the resource is expected to be the name of a dll in the same folder, encoded in UTF8, null terminated, that implements the
CLRDataCreateInterface function. For OS security purposes MinidumpWriteDump will do an authenticode signing check before loading the indicated binary, however if your build isn't CLRDataCreateInterface function. For OS security purposes MinidumpWriteDump will do an authenticode signing check before loading the indicated binary, however if your build isn't
signed you can get around this limitation by registering it at HKLM\Software\Microsoft\WindowsNT\CurrentVersion\MiniDumpAuxilliaryDlls. signed you can get around this limitation by registering it at HKLM\Software\Microsoft\WindowsNT\CurrentVersion\MiniDumpAuxilliaryDlls.
#include <windows.h>
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
#cmakedefine EMBEDDED_MINIDUMP_AUXILIARY_PROVIDER
#ifndef EMBEDDED_MINIDUMP_AUXILIARY_PROVIDER
MINIDUMP_AUXILIARY_PROVIDER RCDATA { "mscordaccore.dll\0" }
#endif
CLRDEBUGINFO RCDATA @CLRDEBUGINFO_RESOURCE_PATH@
\ No newline at end of file
...@@ -7,8 +7,9 @@ ...@@ -7,8 +7,9 @@
<AssemblyName>.NET Runtime</AssemblyName> <AssemblyName>.NET Runtime</AssemblyName>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup Condition="'$(TargetOS)' == 'Windows'">
<ProjectReference Condition="'$(TargetOS)' == 'Windows'" Include="tools/SOS/DacTableGen/DacTableGen.csproj" /> <ProjectReference Include="tools/SOS/DacTableGen/DacTableGen.csproj" />
<ProjectReference Include="tools/InjectResource/InjectResource.csproj" />
</ItemGroup> </ItemGroup>
<Import Project="$(RepositoryEngineeringDir)versioning.targets" /> <Import Project="$(RepositoryEngineeringDir)versioning.targets" />
......
add_subdirectory(SOS) add_subdirectory(SOS)
add_subdirectory(superpmi) add_subdirectory(superpmi)
if (CLR_CMAKE_TARGET_WIN32 AND NOT CLR_CMAKE_CROSS_ARCH)
add_subdirectory(GenClrDebugResource)
add_subdirectory(InjectResource)
install(EXPORT dactabletools DESTINATION dactabletools COMPONENT crosscomponents)
endif()
if (CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64) if (CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64)
add_subdirectory(StressLogAnalyzer) add_subdirectory(StressLogAnalyzer)
endif() endif()
set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded)
add_executable(GenClrDebugResource GenClrDebugResource.cpp)
target_link_libraries(GenClrDebugResource
${STATIC_MT_CRT_LIB}
${STATIC_MT_VCRT_LIB}
)
install(TARGETS GenClrDebugResource EXPORT dactabletools DESTINATION dactabletools COMPONENT crosscomponents)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
/* This app writes out the data for a special resource which is embedded in clr.dll
* The resource serves two purposes, to differentiate a random dll named clr.dll from
* an official microsoft clr dll (it isn't foolproof but it should prevent anyone from
* accidentally appearing to be a clr) and to provide file information about DAC and DBI
* which correspond to this build of the CLR.
*/
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <clrinternal.h>
char* g_appName;
struct ClrDebugResource
{
DWORD dwVersion;
GUID signature;
DWORD dwDacTimeStamp;
DWORD dwDacSizeOfImage;
DWORD dwDbiTimeStamp;
DWORD dwDbiSizeOfImage;
};
BOOL
GetBinFileData(_In_z_ char* binFileName, DWORD* pTimeStamp, DWORD* pSizeOfImage)
{
HANDLE binFileHandle;
DWORD peHeaderOffset;
ULONG done;
binFileHandle = CreateFileA(binFileName, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL);
if (!binFileHandle || binFileHandle == INVALID_HANDLE_VALUE)
{
printf("%s: Unable to open '%s', %d\n", g_appName,
binFileName, GetLastError());
goto error;
}
// Read the 4 byte value at 0x3c, which is the offset to PE header
if (INVALID_SET_FILE_POINTER == SetFilePointer(binFileHandle, 0x3c, NULL, FILE_BEGIN))
{
printf("%s: Unable to move file pointer '%s', %d\n", g_appName,
binFileName, GetLastError());
goto error;
}
if (!ReadFile(binFileHandle, &peHeaderOffset, 4, &done, NULL) ||
done != 4)
{
printf("%s: Unable to read '%s', %d\n", g_appName,
binFileName, GetLastError());
goto error;
}
// Read the 4 byte value at 8 bytes after peHeader, that is the timestamp
if (INVALID_SET_FILE_POINTER == SetFilePointer(binFileHandle, peHeaderOffset + 8, NULL, FILE_BEGIN))
{
printf("%s: Unable to move file pointer '%s', %d\n", g_appName,
binFileName, GetLastError());
goto error;
}
if (!ReadFile(binFileHandle, pTimeStamp, 4, &done, NULL) ||
done != 4)
{
printf("%s: Unable to read '%s', %d\n", g_appName,
binFileName, GetLastError());
goto error;
}
// Read the 4 byte value at 80 bytes after peHeader, that is the sizeOfImage
if (INVALID_SET_FILE_POINTER == SetFilePointer(binFileHandle, peHeaderOffset + 80, NULL, FILE_BEGIN))
{
printf("%s: Unable to move file pointer '%s', %d\n", g_appName,
binFileName, GetLastError());
goto error;
}
if (!ReadFile(binFileHandle, pSizeOfImage, 4, &done, NULL) ||
done != 4)
{
printf("%s: Unable to read '%s', %d\n", g_appName,
binFileName, GetLastError());
goto error;
}
CloseHandle(binFileHandle);
return TRUE;
error:
CloseHandle(binFileHandle);
return FALSE;
}
void
Usage(void)
{
printf("Usage: %s [options]\n", g_appName);
printf("Options are:\n");
printf(" /out:<file> - output binary file that contains the raw resource data\n");
printf(" /dac:<file> - path to mscordacwks that should be referenced\n");
printf(" /dbi:<file> - path to mscordbi that should be referenced\n");
printf(" /sku:<sku_name> - Either clr, coreclr, or phoneclr indicating the CLR sku\n");
}
void __cdecl
main(int argc, _In_z_ char** argv)
{
char* outFile = NULL;
char* dacFile = NULL;
char* dbiFile = NULL;
char* sku = NULL;
g_appName = argv[0];
while (--argc)
{
argv++;
if (!strncmp(*argv, "/out:", 5))
{
outFile = *argv + 5;
}
else if (!strncmp(*argv, "/dac:", 5))
{
dacFile = *argv + 5;
}
else if (!strncmp(*argv, "/dbi:", 5))
{
dbiFile = *argv + 5;
}
else if (!strncmp(*argv, "/sku:", 5))
{
sku = *argv + 5;
}
else
{
Usage();
exit(1);
}
}
if (!outFile || !dacFile || !dbiFile || !sku)
{
Usage();
exit(1);
}
ClrDebugResource res;
res.dwVersion = 0;
if(strcmp(sku, "clr")==0)
{
res.signature = CLR_ID_V4_DESKTOP;
}
else if(strcmp(sku, "coreclr")==0)
{
res.signature = CLR_ID_CORECLR;
}
else if(strcmp(sku, "phoneclr")==0)
{
res.signature = CLR_ID_PHONE_CLR;
}
else if (strcmp(sku, "onecoreclr") == 0)
{
res.signature = CLR_ID_ONECORE_CLR;
}
else
{
printf("Error: Unrecognized sku option: %s\n", sku);
Usage();
exit(1);
}
printf("%s: Reading data from DAC: %s\n", g_appName, dacFile);
if(!GetBinFileData(dacFile, &(res.dwDacTimeStamp), &(res.dwDacSizeOfImage)))
exit(1);
printf("%s: DAC timeStamp = 0x%x sizeOfImage = 0x%x\n", g_appName, res.dwDacTimeStamp, res.dwDacSizeOfImage);
printf("%s: Reading data from DBI: %s\n", g_appName, dbiFile);
if(!GetBinFileData(dbiFile, &(res.dwDbiTimeStamp), &(res.dwDbiSizeOfImage)))
exit(1);
printf("%s: DBI timeStamp = 0x%x sizeOfImage = 0x%x\n", g_appName, res.dwDbiTimeStamp, res.dwDbiSizeOfImage);
printf("%s: Writing binary resource file: %s\n", g_appName, outFile);
HANDLE outFileHandle = CreateFileA(outFile, GENERIC_WRITE, 0,
NULL, CREATE_ALWAYS, 0, NULL);
if (!outFileHandle || outFileHandle == INVALID_HANDLE_VALUE)
{
printf("%s: Unable to create '%s', %d\n",
g_appName, outFile, GetLastError());
goto error;
}
DWORD done = 0;
if(!WriteFile(outFileHandle, &res, sizeof(res), &done, NULL) || done != sizeof(res))
{
printf("%s: Unable to write file data '%s', %d\n",
g_appName, outFile, GetLastError());
goto error;
}
CloseHandle(outFileHandle);
printf("%s: Success. Returning 0\n", g_appName);
exit(0);
error:
CloseHandle(outFileHandle);
exit(1);
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#define FX_VER_FILEDESCRIPTION_STR "Microsoft\0"
#include <fxver.h>
#include <fxver.rc>
remove_definitions(-DUNICODE)
remove_definitions(-D_UNICODE)
set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded)
add_executable(InjectResource InjectResource.cpp)
target_link_libraries(InjectResource
${STATIC_MT_CRT_LIB}
${STATIC_MT_VCRT_LIB}
)
install(TARGETS InjectResource EXPORT dactabletools DESTINATION dactabletools COMPONENT crosscomponents)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <windows.h>
#include <daccess.h>
char* g_appName;
#define MAX(x,y) ((x) > (y) ? (x) : (y))
void
AddBinaryResourceToDll(_In_z_ char* dllName,
_In_z_ const char* resName,
PVOID resData,
ULONG resDataSize)
{
// a retry loop in case we get transient file access issues
// does exponential backoff with retries after 1,2,4,8,16, and 32 seconds
for(int seconds = 0; seconds < 60; seconds = MAX(seconds*2,1))
{
if(seconds != 0)
Sleep(seconds * 1000);
HANDLE dllUpdate = BeginUpdateResourceA(dllName, FALSE);
if (!dllUpdate)
{
printf("Unable to open '%s' for update, error=%d\n",
dllName, GetLastError());
continue;
}
if (!UpdateResourceA(dllUpdate,
(LPCSTR)RT_RCDATA,
resName,
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
resData,
resDataSize))
{
printf("Unable to update '%s', error=%d\n",
dllName, GetLastError());
continue;
}
if(!EndUpdateResource(dllUpdate, FALSE))
{
printf("Unable to write updates to '%s', error=%d\n",
dllName, GetLastError());
continue;
}
return;
}
printf("Stopping after excessive failures\n");
exit(1);
}
void
GetBinFileData(_In_z_ char* binFileName, PVOID* binData, PULONG binDataSize)
{
HANDLE binFileHandle;
PVOID data;
ULONG size, done;
binFileHandle = CreateFileA(binFileName, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL);
if (!binFileHandle || binFileHandle == INVALID_HANDLE_VALUE)
{
printf("Unable to open '%s', %d\n",
binFileName, GetLastError());
exit(1);
}
size = GetFileSize(binFileHandle, NULL);
data = malloc(size);
if (!data)
{
printf("Out of memory\n");
exit(1);
}
if (!ReadFile(binFileHandle, data, size, &done, NULL) ||
done != size)
{
printf("Unable to read '%s', %d\n",
binFileName, GetLastError());
exit(1);
}
CloseHandle(binFileHandle);
*binData = data;
*binDataSize = size;
}
void
Usage(void)
{
printf("Usage: %s [options]\n", g_appName);
printf("Options are:\n");
printf(" /bin:<file> - Binary data to attach to DLL\n");
printf(" /dll:<file> - DLL to modify\n");
printf(" /name:<name> - resource name [Optional]\n");
exit(1);
}
void __cdecl
main(int argc, _In_z_ char** argv)
{
char* binFile = NULL;
char* dllFile = NULL;
char* resName = NULL;
g_appName = argv[0];
while (--argc)
{
argv++;
if (!strncmp(*argv, "/bin:", 5))
{
binFile = *argv + 5;
}
else if (!strncmp(*argv, "/dll:", 5))
{
dllFile = *argv + 5;
}
else if (!strncmp(*argv, "/name:", 6))
{
resName = *argv + 6;
}
else
{
Usage();
}
}
if (!binFile || !dllFile)
{
Usage();
}
PVOID resData;
ULONG resDataSize;
GetBinFileData(binFile, &resData, &resDataSize);
AddBinaryResourceToDll(dllFile, resName?resName:DACCESS_TABLE_RESOURCE,
resData, resDataSize);
free(resData);
printf("Updated %s\n", dllFile);
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>$(NetCoreAppToolCurrent)</TargetFramework>
<Nullable>enable</Nullable>
<Platform>AnyCPU</Platform>
<PlatformTarget>AnyCPU</PlatformTarget>
<IsShipping>false</IsShipping>
<OutputPath>$(RuntimeBinDir)\InjectResource</OutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.CommandLine" Version="$(SystemCommandLineVersion)" />
</ItemGroup>
</Project>
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.CommandLine;
using System.IO;
var binOption = new Option<FileInfo?>(
name: "--bin",
description: "Binary data to attach to the image");
var imageOption = new Option<FileInfo?>(
name: "--image",
description: "PE image to add the binary resource into");
var nameOption = new Option<string>(
name: "--name",
description: "Resource name");
var rootCommand = new RootCommand("Inject native resources into a Portable Executable image");
rootCommand.AddOption(binOption);
rootCommand.AddOption(imageOption);
rootCommand.AddOption(nameOption);
rootCommand.SetHandler(
(FileInfo binaryData, FileInfo peImage, string name) =>
{
using ResourceUpdater updater = new(peImage);
updater.AddBinaryResource(name, File.ReadAllBytes(binaryData.FullName));
},
binOption,
imageOption,
nameOption);
return rootCommand.Invoke(args);
\ No newline at end of file
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
class ResourceUpdater : IDisposable
{
private class UpdateResourceHandle : SafeHandle
{
public UpdateResourceHandle()
:base(IntPtr.Zero, true)
{
}
protected override bool ReleaseHandle()
{
return EndUpdateResource(handle, false);
}
public override bool IsInvalid => handle == IntPtr.Zero;
}
[DllImport("kernel32", EntryPoint = "BeginUpdateResourceA", CharSet = CharSet.Ansi, SetLastError = true)]
private static extern UpdateResourceHandle BeginUpdateResource(string pFileName, bool bDeleteExistingResources);
[DllImport("kernel32", EntryPoint = "UpdateResourceA", CharSet = CharSet.Ansi, SetLastError = true)]
private static extern bool UpdateResource(
UpdateResourceHandle hUpdate,
nint lpType,
string lpName,
ushort wLanguage,
byte[] lpData,
int cb);
[DllImport("kernel32", EntryPoint = "EndUpdateResourceA", CharSet = CharSet.Ansi, SetLastError = true)]
private static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
private UpdateResourceHandle handle;
public ResourceUpdater(FileInfo peFile)
{
handle = BeginUpdateResource(peFile.FullName, false);
if (handle.IsInvalid)
{
throw new Win32Exception(Marshal.GetLastPInvokeError(), peFile.FullName);
}
}
private static readonly nint RT_RCDATA = 10;
private const ushort LANG_NEUTRAL = 0;
public void AddBinaryResource(string name, byte[] data)
{
bool success = UpdateResource(handle, RT_RCDATA, name, LANG_NEUTRAL, data, data.Length);
if (!success)
{
throw new Win32Exception(Marshal.GetLastPInvokeError(), name);
}
}
public void Dispose()
{
handle.Dispose();
}
}
\ No newline at end of file
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#define FX_VER_FILEDESCRIPTION_STR "Microsoft\0"
#include <fxver.h>
#include <fxver.rc>
...@@ -41,7 +41,6 @@ if /i [%1] == [commit] (set __CommitSha=%2&&shift&&shift&goto Arg_Loop) ...@@ -41,7 +41,6 @@ if /i [%1] == [commit] (set __CommitSha=%2&&shift&&shift&goto Arg_Loop)
if /i [%1] == [configureonly] ( set __ConfigureOnly=1&&shift&goto Arg_Loop) if /i [%1] == [configureonly] ( set __ConfigureOnly=1&&shift&goto Arg_Loop)
if /i [%1] == [incremental-native-build] ( set __IncrementalNativeBuild=1&&shift&goto Arg_Loop) if /i [%1] == [incremental-native-build] ( set __IncrementalNativeBuild=1&&shift&goto Arg_Loop)
if /i [%1] == [rootDir] ( set __rootDir=%2&&shift&&shift&goto Arg_Loop) if /i [%1] == [rootDir] ( set __rootDir=%2&&shift&&shift&goto Arg_Loop)
if /i [%1] == [coreclrartifacts] (set __CoreClrArtifacts=%2&&shift&&shift&goto Arg_Loop)
if /i [%1] == [msbuild] (set __Ninja=0) if /i [%1] == [msbuild] (set __Ninja=0)
if /i [%1] == [runtimeflavor] (set __RuntimeFlavor=%2&&shift&&shift&goto Arg_Loop) if /i [%1] == [runtimeflavor] (set __RuntimeFlavor=%2&&shift&&shift&goto Arg_Loop)
if /i [%1] == [runtimeconfiguration] (set __RuntimeConfiguration=%2&&shift&&shift&goto Arg_Loop) if /i [%1] == [runtimeconfiguration] (set __RuntimeConfiguration=%2&&shift&&shift&goto Arg_Loop)
...@@ -129,25 +128,6 @@ IF ERRORLEVEL 1 ( ...@@ -129,25 +128,6 @@ IF ERRORLEVEL 1 (
goto :Failure goto :Failure
) )
if "%__RuntimeFlavor%" NEQ "Mono" (
echo Copying "%__CoreClrArtifacts%\corehost\singlefilehost.exe" "%__CMakeBinDir%/corehost/"
copy /B /Y "%__CoreClrArtifacts%\corehost\singlefilehost.exe" "%__CMakeBinDir%/corehost/"
echo Copying "%__CoreClrArtifacts%\corehost\PDB\singlefilehost.pdb" "%__CMakeBinDir%/corehost/PDB/"
copy /B /Y "%__CoreClrArtifacts%\corehost\PDB\singlefilehost.pdb" "%__CMakeBinDir%/corehost/PDB/"
echo Embedding "%__CoreClrArtifacts%\mscordaccore.dll" into "%__CMakeBinDir%\corehost\singlefilehost.exe"
if not exist "%__CoreClrArtifacts%\x64\dactabletools\InjectResource.exe" (
"%__CoreClrArtifacts%\dactabletools\InjectResource.exe" /bin:"%__CoreClrArtifacts%\mscordaccore.dll" /dll:"%__CMakeBinDir%\corehost\singlefilehost.exe" /name:MINIDUMP_EMBEDDED_AUXILIARY_PROVIDER
) else (
"%__CoreClrArtifacts%\x64\dactabletools\InjectResource.exe" /bin:"%__CoreClrArtifacts%\mscordaccore.dll" /dll:"%__CMakeBinDir%\corehost\singlefilehost.exe" /name:MINIDUMP_EMBEDDED_AUXILIARY_PROVIDER
)
IF ERRORLEVEL 1 (
goto :Failure
)
)
echo Done building Native components echo Done building Native components
:Exit :Exit
......
...@@ -57,11 +57,6 @@ handle_arguments() { ...@@ -57,11 +57,6 @@ handle_arguments() {
__ShiftArgs=1 __ShiftArgs=1
;; ;;
coreclrartifacts|-coreclrartifacts)
__CoreClrArtifacts="$2"
__ShiftArgs=1
;;
runtimeflavor|-runtimeflavor) runtimeflavor|-runtimeflavor)
__RuntimeFlavor="$2" __RuntimeFlavor="$2"
__ShiftArgs=1 __ShiftArgs=1
...@@ -83,7 +78,7 @@ __DistroRidLower="$(echo $__DistroRid | tr '[:upper:]' '[:lower:]')" ...@@ -83,7 +78,7 @@ __DistroRidLower="$(echo $__DistroRid | tr '[:upper:]' '[:lower:]')"
__BinDir="$__RootBinDir/bin/$__DistroRidLower.$__BuildType" __BinDir="$__RootBinDir/bin/$__DistroRidLower.$__BuildType"
__IntermediatesDir="$__RootBinDir/obj/$__DistroRidLower.$__BuildType" __IntermediatesDir="$__RootBinDir/obj/$__DistroRidLower.$__BuildType"
export __BinDir __IntermediatesDir __CoreClrArtifacts __RuntimeFlavor export __BinDir __IntermediatesDir __RuntimeFlavor
__CMakeArgs="-DCLI_CMAKE_HOST_VER=\"$__host_ver\" -DCLI_CMAKE_COMMON_HOST_VER=\"$__apphost_ver\" -DCLI_CMAKE_HOST_FXR_VER=\"$__fxr_ver\" $__CMakeArgs" __CMakeArgs="-DCLI_CMAKE_HOST_VER=\"$__host_ver\" -DCLI_CMAKE_COMMON_HOST_VER=\"$__apphost_ver\" -DCLI_CMAKE_HOST_FXR_VER=\"$__fxr_ver\" $__CMakeArgs"
__CMakeArgs="-DCLI_CMAKE_HOST_POLICY_VER=\"$__policy_ver\" -DCLI_CMAKE_PKG_RID=\"$__DistroRid\" -DCLI_CMAKE_COMMIT_HASH=\"$__commit_hash\" $__CMakeArgs" __CMakeArgs="-DCLI_CMAKE_HOST_POLICY_VER=\"$__policy_ver\" -DCLI_CMAKE_PKG_RID=\"$__DistroRid\" -DCLI_CMAKE_COMMIT_HASH=\"$__commit_hash\" $__CMakeArgs"
...@@ -103,8 +98,3 @@ check_prereqs ...@@ -103,8 +98,3 @@ check_prereqs
# Build the installer native components. # Build the installer native components.
build_native "$__TargetOS" "$__BuildArch" "$__scriptpath" "$__IntermediatesDir" "install" "$__CMakeArgs" "installer component" build_native "$__TargetOS" "$__BuildArch" "$__scriptpath" "$__IntermediatesDir" "install" "$__CMakeArgs" "installer component"
if [[ "$__RuntimeFlavor" != "Mono" ]]; then
echo Copying "$__CoreClrArtifacts/corehost/." to "$__CMakeBinDir/corehost"
cp -a "$__CoreClrArtifacts/corehost/." "$__CMakeBinDir/corehost"
fi
...@@ -11,6 +11,41 @@ ...@@ -11,6 +11,41 @@
<IntermediateOutputRootPath>$(ArtifactsObjDir)$(OutputRid).$(Configuration)\</IntermediateOutputRootPath> <IntermediateOutputRootPath>$(ArtifactsObjDir)$(OutputRid).$(Configuration)\</IntermediateOutputRootPath>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<ProjectReference Include="$(CoreClrProjectRoot)tools/InjectResource/InjectResource.csproj" ReferenceOutputAssembly="false" OutputItemType="InjectResourceTool"/>
</ItemGroup>
<Target Name="PrepareSingleFileHostWithEmbeddedDacPrereqs">
<PropertyGroup>
<SingleFileHostPath>$(CoreCLRArtifactsPath)/corehost/singlefilehost$(ExeSuffix)</SingleFileHostPath>
<SingleFileHostSymbolsPath>$(CoreCLRArtifactsPath)/corehost/PDB/singlefilehost$(SymbolsSuffix)</SingleFileHostSymbolsPath>
<DacPath>$(CoreCLRArtifactsPath)/mscordaccore$(LibSuffix)</DacPath>
<SingleFileHostDestinationPath>$(DotNetHostBinDir)/singlefilehost$(ExeSuffix)</SingleFileHostDestinationPath>
<SingleFileHostSymbolsDestinationPath>$(DotNetHostBinDir)/PDB/singlefilehost$(SymbolsSuffix)</SingleFileHostSymbolsDestinationPath>
</PropertyGroup>
</Target>
<!--
Target that copies the singlefilehost and embeds the DAC into it.
We embed the DAC now instead of during the native build because we need to sign the DAC and signing the DAC during CMake would be ugly.
-->
<Target Name="PrepareSingleFileHostWithEmbeddedDacCore"
Inputs="$(SingleFileHostPath);
$(SingleFileHostSymbolsPath);
$(DacPath);
@(InjectResourceTool)"
Outputs="$(SingleFileHostDestinationPath);$(SingleFileHostSymbolsDestinationPath)"
DependsOnTargets="ResolveProjectReferences"
Condition="'$(RuntimeFlavor)' != 'Mono'">
<Copy SourceFiles="$(SingleFileHostPath);$(SingleFileHostSymbolsPath)" DestinationFiles="$(SingleFileHostDestinationPath);$(SingleFileHostSymbolsPath)" />
<Exec Condition="'$(TargetOS)' == 'windows'"
Command="$(NetCoreRoot)dotnet exec @(InjectResourceTool) --bin &quot;$(DacPath)&quot; --image &quot;$(SingleFileHostDestinationPath)&quot; --name MINIDUMP_EMBEDDED_AUXILIARY_PROVIDER" />
</Target>
<Target Name="PrepareSingleFileHostWithEmbeddedDac"
DependsOnTargets="PrepareSingleFileHostWithEmbeddedDacPrereqs;PrepareSingleFileHostWithEmbeddedDacCore"
AfterTargets="Build"/>
<!-- Target that builds dotnet, hostfxr and hostpolicy with the same version as what NetCoreApp will be built for <!-- Target that builds dotnet, hostfxr and hostpolicy with the same version as what NetCoreApp will be built for
since the build produced artifacts should always version the same (even if they may not get used). since the build produced artifacts should always version the same (even if they may not get used).
--> -->
...@@ -30,7 +65,6 @@ ...@@ -30,7 +65,6 @@
<BuildArgs Condition="'$(CrossBuild)' == 'true'">$(BuildArgs) -cross</BuildArgs> <BuildArgs Condition="'$(CrossBuild)' == 'true'">$(BuildArgs) -cross</BuildArgs>
<BuildArgs Condition="'$(Compiler)' != ''">$(BuildArgs) $(Compiler)</BuildArgs> <BuildArgs Condition="'$(Compiler)' != ''">$(BuildArgs) $(Compiler)</BuildArgs>
<BuildArgs Condition="'$(CMakeArgs)' != ''">$(BuildArgs) $(CMakeArgs)</BuildArgs> <BuildArgs Condition="'$(CMakeArgs)' != ''">$(BuildArgs) $(CMakeArgs)</BuildArgs>
<BuildArgs>$(BuildArgs) -coreclrartifacts $(CoreCLRArtifactsPath)</BuildArgs>
<BuildArgs Condition="'$(Ninja)' == 'true'">$(BuildArgs) -ninja</BuildArgs> <BuildArgs Condition="'$(Ninja)' == 'true'">$(BuildArgs) -ninja</BuildArgs>
<BuildArgs>$(BuildArgs) -runtimeflavor $(RuntimeFlavor)</BuildArgs> <BuildArgs>$(BuildArgs) -runtimeflavor $(RuntimeFlavor)</BuildArgs>
<BuildArgs Condition="'$(OfficialBuildId)' != ''">$(BuildArgs) /p:OfficialBuildId="$(OfficialBuildId)"</BuildArgs> <BuildArgs Condition="'$(OfficialBuildId)' != ''">$(BuildArgs) /p:OfficialBuildId="$(OfficialBuildId)"</BuildArgs>
...@@ -89,7 +123,6 @@ ...@@ -89,7 +123,6 @@
<BuildArgs Condition="'$(PortableBuild)' == 'true'">$(BuildArgs) portable</BuildArgs> <BuildArgs Condition="'$(PortableBuild)' == 'true'">$(BuildArgs) portable</BuildArgs>
<BuildArgs Condition="'$(IncrementalNativeBuild)' == 'true'">$(BuildArgs) incremental-native-build</BuildArgs> <BuildArgs Condition="'$(IncrementalNativeBuild)' == 'true'">$(BuildArgs) incremental-native-build</BuildArgs>
<BuildArgs>$(BuildArgs) rootdir $(RepoRoot)</BuildArgs> <BuildArgs>$(BuildArgs) rootdir $(RepoRoot)</BuildArgs>
<BuildArgs>$(BuildArgs) coreclrartifacts $(CoreCLRArtifactsPath)</BuildArgs>
<BuildArgs Condition="'$(Ninja)' == 'false'">$(BuildArgs) msbuild</BuildArgs> <BuildArgs Condition="'$(Ninja)' == 'false'">$(BuildArgs) msbuild</BuildArgs>
<BuildArgs>$(BuildArgs) runtimeflavor $(RuntimeFlavor)</BuildArgs> <BuildArgs>$(BuildArgs) runtimeflavor $(RuntimeFlavor)</BuildArgs>
<BuildArgs>$(BuildArgs) runtimeconfiguration $(RuntimeConfiguration)</BuildArgs> <BuildArgs>$(BuildArgs) runtimeconfiguration $(RuntimeConfiguration)</BuildArgs>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册