1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
6 // TO DO: we currently use raw printf() for output. Maybe we need to pick up something like ngen's Output() handling
7 // to handle multiple code pages, etc, better.
23 #include "consoleargs.h"
25 // Return values from wmain() in case of error
30 ASSEMBLY_NOT_FOUND = -3,
31 INVALID_ARGUMENTS = -4
34 #define NumItems(s) (sizeof(s) / sizeof(s[0]))
36 STDAPI CreatePDBWorker(LPCWSTR pwzAssemblyPath, LPCWSTR pwzPlatformAssembliesPaths, LPCWSTR pwzTrustedPlatformAssemblies, LPCWSTR pwzPlatformResourceRoots, LPCWSTR pwzAppPaths, LPCWSTR pwzAppNiPaths, LPCWSTR pwzPdbPath, BOOL fGeneratePDBLinesInfo, LPCWSTR pwzManagedPdbSearchPath, LPCWSTR pwzPlatformWinmdPaths, LPCWSTR pwzDiasymreaderPath);
37 STDAPI NGenWorker(LPCWSTR pwzFilename, DWORD dwFlags, LPCWSTR pwzPlatformAssembliesPaths, LPCWSTR pwzTrustedPlatformAssemblies, LPCWSTR pwzPlatformResourceRoots, LPCWSTR pwzAppPaths, LPCWSTR pwzOutputFilename=NULL, LPCWSTR pwzPlatformWinmdPaths=NULL, ICorSvcLogger *pLogger = NULL, LPCWSTR pwszCLRJITPath = nullptr);
38 void SetSvcLogger(ICorSvcLogger *pCorSvcLogger);
39 void SetMscorlibPath(LPCWSTR wzSystemDirectory);
41 /* --------------------------------------------------------------------------- *
43 * --------------------------------------------------------------------------- */
45 void Output(LPCWSTR str)
47 wprintf(W("%s"), str);
50 void Outputf(LPCWSTR szFormat, ...)
53 va_start(args, szFormat);
54 vfwprintf(stdout, szFormat, args);
58 void OutputErr(LPCWSTR str)
60 fwprintf(stderr, W("%s"), str);
63 void OutputErrf(LPCWSTR szFormat, ...)
66 va_start(args, szFormat);
67 vfwprintf(stderr, szFormat, args);
71 void ErrorHR(HRESULT hr)
73 OutputErrf(W("Error: failed to initialize CoreCLR: 0x%08x\n"), hr);
76 void ErrorWin32(DWORD err)
78 ErrorHR(HRESULT_FROM_WIN32(err));
81 // Some error messages are useless to callers, so make them generic, except in debug builds, where we want as much
82 // information as possible.
85 #define ERROR_HR(msg,hr) Outputf(msg, hr)
86 #define ERROR_WIN32(msg,err) Outputf(msg, err)
88 #define ERROR_HR(msg,hr) ErrorHR(hr)
89 #define ERROR_WIN32(msg,err) ErrorWin32(err)
93 void PrintLogoHelper()
95 Output(W("Microsoft (R) CoreCLR Native Image "));
96 Outputf(W("Generator - Version %S\n"), VER_FILEVERSION_STR);
97 Outputf(W("%S\n"), VER_LEGALCOPYRIGHT_LOGO_STR);
101 void PrintUsageHelper()
103 // Always print the logo when we print the usage, even if they've specified /nologo and we've parsed that already.
107 W("Usage: crossgen [args] <assembly name>\n")
109 W(" /? or /help - Display this screen\n")
110 W(" /nologo - Prevents displaying the logo\n")
111 W(" /silent - Do not display completion message\n")
112 W(" /verbose - Display verbose information\n")
113 W(" @response.rsp - Process command line arguments from specified\n")
114 W(" response file\n")
115 W(" /in <file> - Specifies input filename (optional)\n")
116 W(" /out <file> - Specifies output filename (optional)\n")
117 W(" /Trusted_Platform_Assemblies <path[") PATH_SEPARATOR_STR_W W("path]>\n")
118 W(" - List of assemblies treated as trusted platform\n")
119 W(" - Cannot be used with Platform_Assemblies_Paths\n")
120 W(" /Platform_Resource_Roots <path[") PATH_SEPARATOR_STR_W W("path]>\n")
121 W(" - List of paths containing localized assembly directories\n")
122 W(" /App_Paths <path[") PATH_SEPARATOR_STR_W W("path]>\n")
123 W(" - List of paths containing user-application assemblies and resources\n")
125 W(" /App_Ni_Paths <path[") PATH_SEPARATOR_STR_W W("path]>\n")
126 W(" - List of paths containing user-application native images\n")
127 W(" - Must be used with /CreatePDB switch\n")
130 W(" /Platform_Assemblies_Paths <path[") PATH_SEPARATOR_STR_W W("path]>\n")
131 W(" - List of paths containing target platform assemblies\n")
132 // If Platform_Assemblies_Paths, we will use it to build the TPA list and thus,
133 // TPA list cannot be explicitly specified.
134 W(" - Cannot be used with Trusted_Platform_Assemblies\n")
136 #ifdef FEATURE_COMINTEROP
137 W(" /Platform_Winmd_Paths <path[") PATH_SEPARATOR_STR_W W("path]>\n")
138 W(" - List of paths containing target platform WinMDs used\n")
139 W(" for emulating RoResolveNamespace\n")
141 W(" /MissingDependenciesOK\n")
142 W(" - Specifies that crossgen should attempt not to fail\n")
143 W(" if a dependency is missing.\n")
145 W(" /Tuning - Generate an instrumented image to collect\n")
146 W(" scenario traces, which can be used with ibcmerge.exe\n")
148 #if !defined(FEATURE_MERGE_JIT_AND_ENGINE)
149 W(" /JITPath <path>\n")
150 W(" - Specifies the absolute file path to JIT compiler to be used.\n")
151 #endif // !defined(FEATURE_MERGE_JIT_AND_ENGINE)
152 #ifdef FEATURE_READYTORUN_COMPILER
153 W(" /ReadyToRun - Generate images resilient to the runtime and\n")
154 W(" dependency versions\n")
156 #ifdef FEATURE_WINMD_RESILIENT
157 W(" WinMD Parameters\n")
158 W(" /WinMDResilient - Generate images resilient to WinMD dependency changes.\n")
160 W(" Size on Disk Parameters\n")
161 W(" /NoMetaData - Do not copy metadata and IL into native image.\n")
163 W(" Debugging Parameters\n")
164 W(" /CreatePDB <Dir to store PDB> [/lines [<search path for managed PDB>] ]\n")
165 W(" When specifying /CreatePDB, the native image should be created\n")
166 W(" first, and <assembly name> should be the path to the NI.\n")
167 W(" /DiasymreaderPath <Path to diasymreader.dll>\n")
168 W(" - Specifies the absolute file path to diasymreader.dll to be used.\n")
169 #elif defined(FEATURE_PERFMAP)
170 W(" Debugging Parameters\n")
171 W(" /CreatePerfMap <Dir to store perf map>\n")
172 W(" When specifying /CreatePerfMap, the native image should be created\n")
173 W(" first, and <assembly name> should be the path to the NI.\n")
178 class CrossgenLogger : public ICorSvcLogger
180 STDMETHODIMP_(ULONG) AddRef() {return E_NOTIMPL;}
181 STDMETHODIMP_(ULONG) Release() {return E_NOTIMPL;}
182 STDMETHODIMP QueryInterface(REFIID riid,void ** ppv)
189 if (IsEqualIID(riid, IID_ICorSvcLogger) || IsEqualIID(riid, IID_IUnknown))
196 return E_NOINTERFACE;
200 HRESULT STDMETHODCALLTYPE Log(
201 /*[in] */CorSvcLogLevel logLevel,
202 /*[in] */BSTR message
205 if (logLevel == LogLevel_Error)
213 CrossgenLogger g_CrossgenLogger;
216 // Tests whether szArg, the currently indexed argv matches the specified parameter name, szTestParamName.
217 // Specify szTestParamName without a switch. This method handles testing for - and / switches.
219 bool MatchParameter(LPCWSTR szArg, LPCWSTR szTestParamName)
221 if (wcslen(szArg) == 0)
226 if (szArg[0] != W('/') && szArg[0] != W('-'))
231 return !_wcsicmp(szArg + 1, szTestParamName) || !_wcsicmp(szArg + 1, szTestParamName);
235 // Returns true if pwzString ends with the string in pwzCandidate
238 bool StringEndsWith(LPCWSTR pwzString, LPCWSTR pwzCandidate)
240 size_t stringLength = wcslen(pwzString);
241 size_t candidateLength = wcslen(pwzCandidate);
243 if (candidateLength > stringLength || stringLength == 0 || candidateLength == 0)
248 LPCWSTR pwzStringEnd = pwzString + stringLength - candidateLength;
250 return !_wcsicmp(pwzStringEnd, pwzCandidate);
254 // When using the Phone binding model (TrustedPlatformAssemblies), automatically
255 // detect which path CoreLib.[ni.]dll lies in.
257 bool ComputeMscorlibPathFromTrustedPlatformAssemblies(SString& pwzMscorlibPath, LPCWSTR pwzTrustedPlatformAssemblies)
259 LPWSTR wszTrustedPathCopy = new WCHAR[wcslen(pwzTrustedPlatformAssemblies) + 1];
260 wcscpy_s(wszTrustedPathCopy, wcslen(pwzTrustedPlatformAssemblies) + 1, pwzTrustedPlatformAssemblies);
262 LPWSTR wszSingleTrustedPath = wcstok_s(wszTrustedPathCopy, PATH_SEPARATOR_STR_W, &context);
264 while (wszSingleTrustedPath != NULL)
266 size_t pathLength = wcslen(wszSingleTrustedPath);
267 // Strip off enclosing quotes, if present
268 if (wszSingleTrustedPath[0] == W('\"') && wszSingleTrustedPath[pathLength-1] == W('\"'))
270 wszSingleTrustedPath[pathLength-1] = '\0';
271 wszSingleTrustedPath++;
274 if (StringEndsWith(wszSingleTrustedPath, DIRECTORY_SEPARATOR_STR_W CoreLibName_IL_W) ||
275 StringEndsWith(wszSingleTrustedPath, DIRECTORY_SEPARATOR_STR_W CoreLibName_NI_W))
277 pwzMscorlibPath.Set(wszSingleTrustedPath);
278 SString::Iterator pwzSeparator = pwzMscorlibPath.End();
281 if (!SUCCEEDED(CopySystemDirectory(pwzMscorlibPath, pwzMscorlibPath)))
286 delete [] wszTrustedPathCopy;
290 wszSingleTrustedPath = wcstok_s(NULL, PATH_SEPARATOR_STR_W, &context);
292 delete [] wszTrustedPathCopy;
297 // Given a path terminated with "\\" and a search mask, this function will add
298 // the enumerated files, corresponding to the search mask, from the path into
300 void PopulateTPAList(SString path, LPCWSTR pwszMask, SString &refTPAList, bool fCompilingMscorlib, bool fCreatePDB)
302 _ASSERTE(path.GetCount() > 0);
303 ClrDirectoryEnumerator folderEnumerator(path.GetUnicode(), pwszMask);
305 while (folderEnumerator.Next())
307 // Got a valid enumeration handle and the data about the first file.
308 DWORD dwAttributes = folderEnumerator.GetFileAttributes();
309 if ((!(dwAttributes & FILE_ATTRIBUTE_DIRECTORY)) && (!(dwAttributes & FILE_ATTRIBUTE_DEVICE)))
311 bool fAddDelimiter = (refTPAList.GetCount() > 0)?true:false;
312 bool fAddFileToTPAList = true;
313 LPCWSTR pwszFilename = folderEnumerator.GetFileName();
315 // No NIs are supported when creating NI images (other than NI of System.Private.CoreLib.dll).
318 // Only CoreLib's ni.dll should be in the TPAList for the compilation of non-mscorlib assemblies.
319 if (StringEndsWith((LPWSTR)pwszFilename, W(".ni.dll")))
321 fAddFileToTPAList = false;
325 if (fAddFileToTPAList)
329 // Add the path delimiter if we already have entries in the TPAList
330 refTPAList.Append(PATH_SEPARATOR_CHAR_W);
332 // Add the path to the TPAList
333 refTPAList.Append(path);
334 refTPAList.Append(pwszFilename);
340 // Given a semi-colon delimited set of absolute folder paths (pwzPlatformAssembliesPaths), this function
341 // will enumerate all EXE/DLL modules in those folders and add them to the TPAList buffer (refTPAList).
342 void ComputeTPAListFromPlatformAssembliesPath(LPCWSTR pwzPlatformAssembliesPaths, SString &refTPAList, bool fCompilingMscorlib, bool fCreatePDB)
344 // We should have a valid pointer to the paths
345 _ASSERTE(pwzPlatformAssembliesPaths != NULL);
347 SString ssPlatformAssembliesPath(pwzPlatformAssembliesPaths);
349 // Platform Assemblies Path List is semi-colon delimited
350 if(ssPlatformAssembliesPath.GetCount() > 0)
352 SString::CIterator start = ssPlatformAssembliesPath.Begin();
353 SString::CIterator itr = ssPlatformAssembliesPath.Begin();
354 SString::CIterator end = ssPlatformAssembliesPath.End();
355 SString qualifiedPath;
360 BOOL found = ssPlatformAssembliesPath.Find(itr, PATH_SEPARATOR_CHAR_W);
366 SString qualifiedPath(ssPlatformAssembliesPath,start,itr);
373 unsigned len = qualifiedPath.GetCount();
377 if (qualifiedPath[len-1]!=DIRECTORY_SEPARATOR_CHAR_W)
379 qualifiedPath.Append(DIRECTORY_SEPARATOR_CHAR_W);
382 // Enumerate the EXE/DLL modules within this path and add them to the TPAList
385 PopulateTPAList(qualifiedPath, W("*.exe"), refTPAList, fCompilingMscorlib, fCreatePDB);
386 PopulateTPAList(qualifiedPath, W("*.dll"), refTPAList, fCompilingMscorlib, fCreatePDB);
390 Outputf(W("Warning: Error enumerating files under %s.\n"), qualifiedPath.GetUnicode());
392 EX_END_CATCH(SwallowAllExceptions);
398 extern HMODULE g_hThisInst;
400 int _cdecl wmain(int argc, __in_ecount(argc) WCHAR **argv)
403 g_hThisInst = WszGetModuleHandle(NULL);
406 /////////////////////////////////////////////////////////////////////////
408 // Parse the arguments
410 bool fDisplayLogo = true;
412 LPCWSTR pwzFilename = NULL;
413 LPCWSTR pwzPlatformResourceRoots = nullptr;
414 LPCWSTR pwzTrustedPlatformAssemblies = nullptr;
415 LPCWSTR pwzAppPaths = nullptr;
416 LPCWSTR pwzAppNiPaths = nullptr;
417 LPCWSTR pwzPlatformAssembliesPaths = nullptr;
418 LPCWSTR pwzPlatformWinmdPaths = nullptr;
419 StackSString wzDirectoryToStorePDB;
420 bool fCreatePDB = false;
421 bool fGeneratePDBLinesInfo = false;
422 LPWSTR pwzSearchPathForManagedPDB = NULL;
423 LPCWSTR pwzOutputFilename = NULL;
424 LPCWSTR pwzPublicKeys = nullptr;
426 #if !defined(FEATURE_MERGE_JIT_AND_ENGINE)
427 LPCWSTR pwszCLRJITPath = nullptr;
428 #endif // !defined(FEATURE_MERGE_JIT_AND_ENGINE)
430 LPCWSTR pwzDiasymreaderPath = nullptr;
434 #ifndef PLATFORM_UNIX
435 // This is required to properly display Unicode characters
436 _setmode(_fileno(stdout), _O_U8TEXT);
439 // Skip this executable path
443 ConsoleArgs consoleArgs;
450 exit(INVALID_ARGUMENTS);
453 if (!consoleArgs.ExpandResponseFiles(argc, argv, &argc2, &argv2))
455 if (consoleArgs.ErrorMessage() != nullptr)
457 wprintf(consoleArgs.ErrorMessage());
458 exit(FAILURE_RESULT);
465 // By default, Crossgen will generate readytorun images unless /FragileNonVersionable switch is specified
466 dwFlags |= NGENWORKER_FLAGS_READYTORUN;
470 if (MatchParameter(*argv, W("?"))
471 || MatchParameter(*argv, W("help")))
474 exit(INVALID_ARGUMENTS);
476 else if (MatchParameter(*argv, W("nologo")))
478 fDisplayLogo = false;
480 else if (MatchParameter(*argv, W("silent")))
482 dwFlags |= NGENWORKER_FLAGS_SILENT;
484 else if (MatchParameter(*argv, W("verbose")))
486 dwFlags |= NGENWORKER_FLAGS_VERBOSE;
488 else if (MatchParameter(*argv, W("Tuning")))
490 dwFlags |= NGENWORKER_FLAGS_TUNING;
492 else if (MatchParameter(*argv, W("MissingDependenciesOK")))
494 dwFlags |= NGENWORKER_FLAGS_MISSINGDEPENDENCIESOK;
496 #if !defined(FEATURE_MERGE_JIT_AND_ENGINE)
497 else if (MatchParameter(*argv, W("JITPath")) && (argc > 1))
499 pwszCLRJITPath = argv[1];
505 #endif // !defined(FEATURE_MERGE_JIT_AND_ENGINE)
506 #ifdef FEATURE_WINMD_RESILIENT
507 else if (MatchParameter(*argv, W("WinMDResilient")))
509 dwFlags |= NGENWORKER_FLAGS_WINMD_RESILIENT;
512 #ifdef FEATURE_READYTORUN_COMPILER
513 else if (MatchParameter(*argv, W("ReadyToRun")))
515 dwFlags |= NGENWORKER_FLAGS_READYTORUN;
517 else if (MatchParameter(*argv, W("FragileNonVersionable")))
519 dwFlags &= ~NGENWORKER_FLAGS_READYTORUN;
522 else if (MatchParameter(*argv, W("NoMetaData")))
524 dwFlags |= NGENWORKER_FLAGS_NO_METADATA;
526 else if (MatchParameter(*argv, W("out")))
528 if (pwzOutputFilename != NULL)
530 Output(W("Cannot specify multiple output files.\n"));
531 exit(INVALID_ARGUMENTS);
533 pwzOutputFilename = argv[1];
537 else if (MatchParameter(*argv, W("in")))
539 if (pwzFilename != NULL)
541 Output(W("Cannot specify multiple input files.\n"));
542 exit(INVALID_ARGUMENTS);
544 pwzFilename = argv[1];
548 else if (MatchParameter(*argv, W("Trusted_Platform_Assemblies")) && (argc > 1))
550 pwzTrustedPlatformAssemblies = argv[1];
556 else if (MatchParameter(*argv, W("Platform_Resource_Roots")) && (argc > 1))
558 pwzPlatformResourceRoots = argv[1];
564 else if (MatchParameter(*argv, W("App_Paths")) && (argc > 1))
566 pwzAppPaths = argv[1];
568 // skip User app path
573 else if (MatchParameter(*argv, W("App_Ni_Paths")) && (argc > 1))
575 pwzAppNiPaths = argv[1];
577 // skip User app path
582 else if (MatchParameter(*argv, W("Platform_Assemblies_Paths")) && (argc > 1))
584 pwzPlatformAssembliesPaths = argv[1];
590 #ifdef FEATURE_COMINTEROP
591 else if (MatchParameter(*argv, W("Platform_Winmd_Paths")) && (argc > 1))
593 pwzPlatformWinmdPaths = argv[1];
595 // skip User app path
599 #endif // FEATURE_COMINTEROP
601 else if (MatchParameter(*argv, W("CreatePDB")) && (argc > 1))
603 // syntax: /CreatePDB <directory to store PDB> [/lines [<search path for managed PDB>] ]
610 // Clear any extra flags - using /CreatePDB fails if any of these are set.
611 dwFlags = dwFlags & ~NGENWORKER_FLAGS_READYTORUN;
613 // Parse: <directory to store PDB>
614 wzDirectoryToStorePDB.Set(argv[0]);
618 // Ensure output dir ends in a backslash, or else diasymreader has issues
619 if (wzDirectoryToStorePDB[wzDirectoryToStorePDB.GetCount()-1] != DIRECTORY_SEPARATOR_CHAR_W)
621 wzDirectoryToStorePDB.Append(DIRECTORY_SEPARATOR_STR_W);
626 Output(W("The /CreatePDB switch requires <directory to store PDB> and <assembly name>.\n"));
627 exit(FAILURE_RESULT);
630 // [/lines [<search path for managed PDB>] ]
631 if (MatchParameter(*argv, W("lines")) && (argc > 1))
634 fGeneratePDBLinesInfo = true;
640 Output(W("The /CreatePDB switch requires <directory to store PDB> and <assembly name>.\n"));
641 exit(FAILURE_RESULT);
646 // Parse: <search path for managed PDB>
647 pwzSearchPathForManagedPDB = argv[0];
653 // Undo last arg iteration, since we do it for all cases at the bottom of
658 else if (MatchParameter(*argv, W("DiasymreaderPath")) && (argc > 1))
660 pwzDiasymreaderPath = argv[1];
662 // skip diasymreader Path
667 #ifdef FEATURE_PERFMAP
668 else if (MatchParameter(*argv, W("CreatePerfMap")) && (argc > 1))
670 // syntax: /CreatePerfMap <directory to store perfmap>
672 // Parse: /CreatePerfMap
673 // NOTE: We use the same underlying PDB logic.
678 // Clear the /ready to run flag - /CreatePerfmap does not work with any other flags.
679 dwFlags = dwFlags & ~NGENWORKER_FLAGS_READYTORUN;
681 // Parse: <directory to store PDB>
682 wzDirectoryToStorePDB.Set(argv[0]);
686 // Ensure output dir ends in a backslash
687 if (wzDirectoryToStorePDB[wcslen(wzDirectoryToStorePDB)-1] != DIRECTORY_SEPARATOR_CHAR_W)
689 wzDirectoryToStorePDB.Append(DIRECTORY_SEPARATOR_STR_W);
694 Output(W("The /CreatePerfMap switch requires <directory to store perfmap> and <assembly name>.\n"));
695 exit(FAILURE_RESULT);
698 // Undo last arg iteration, since we do it for all cases at the bottom of
703 #endif // FEATURE_PERFMAP
708 #if !defined(FEATURE_PAL)
709 // When not running on Mac, which can have forward-slash pathnames, we know
710 // a command switch here means an invalid argument.
711 if (*argv[0] == W('-') || *argv[0] == W('/'))
713 Outputf(W("Invalid parameter: %s\n"), *argv);
714 exit(INVALID_ARGUMENTS);
716 #endif //!FEATURE_PAL
717 // The last thing on the command line is an assembly name or path, and
718 // because we got this far is not an argument like /nologo. Because this
719 // code works on Mac, with forward-slash pathnames, we can't assume
720 // anything with a forward slash is an argument. So we just always
721 // assume the last thing on the command line must be an assembly name.
723 if (pwzFilename != NULL)
725 Output(W("Cannot use /In and specify an input file as the last argument.\n"));
726 exit(INVALID_ARGUMENTS);
734 Outputf(W("Invalid parameter: %s\n"), *argv);
735 exit(INVALID_ARGUMENTS);
743 if (pwzFilename == NULL)
745 Output(W("You must specify an assembly to compile\n"));
746 exit(INVALID_ARGUMENTS);
749 if (fCreatePDB && (dwFlags != 0))
751 Output(W("The /CreatePDB switch cannot be used with other switches, except /lines and the various path switches.\n"));
752 exit(FAILURE_RESULT);
755 if (pwzAppNiPaths != nullptr && !fCreatePDB)
757 Output(W("The /App_Ni_Paths switch can only be used with the /CreatePDB switch.\n"));
758 exit(FAILURE_RESULT);
761 #if !defined(FEATURE_MERGE_JIT_AND_ENGINE)
762 if (pwszCLRJITPath != nullptr && fCreatePDB)
764 Output(W("The /JITPath switch can not be used with the /CreatePDB switch.\n"));
765 exit(FAILURE_RESULT);
767 #endif // !defined(FEATURE_MERGE_JIT_AND_ENGINE)
769 #if !defined(NO_NGENPDB)
770 if (pwzDiasymreaderPath != nullptr && !fCreatePDB)
772 Output(W("The /DiasymreaderPath switch can only be used with the /CreatePDB switch.\n"));
773 exit(FAILURE_RESULT);
775 #endif // !defined(NO_NGENPDB)
777 if ((pwzTrustedPlatformAssemblies != nullptr) && (pwzPlatformAssembliesPaths != nullptr))
779 Output(W("The /Trusted_Platform_Assemblies and /Platform_Assemblies_Paths switches cannot be both specified.\n"));
780 exit(FAILURE_RESULT);
783 if ((dwFlags & NGENWORKER_FLAGS_NO_METADATA) != 0)
785 const size_t windowsDotWinmdLength = 13; // Length of string "Windows.winmd"
786 size_t filenameLength = wcslen(pwzFilename);
787 bool isWindowsDotWinmd = true;
788 if (filenameLength < windowsDotWinmdLength ||
789 _wcsicmp(pwzFilename + filenameLength - windowsDotWinmdLength, W("windows.winmd")) != 0)
791 isWindowsDotWinmd = false;
793 else if (filenameLength > windowsDotWinmdLength)
795 WCHAR pathSeparator = pwzFilename[filenameLength - windowsDotWinmdLength - 1];
796 if (pathSeparator != W('\\') && pathSeparator != W('/') && pathSeparator != W(':'))
798 isWindowsDotWinmd = false;
801 if (!isWindowsDotWinmd)
803 Output(W("The /NoMetaData switch can only be used with Windows.winmd.\n"));
804 exit(FAILURE_RESULT);
808 // All argument processing has happened by now. The only messages that should appear before here are errors
809 // related to argument parsing, such as the Usage message. Afterwards, other messages can appear.
811 /////////////////////////////////////////////////////////////////////////
821 PathString wzTrustedPathRoot;
827 // While creating PDB, assembly binder gives preference to files in TPA.
828 // This can create difficulties if the input file is not in TPA.
829 // To avoid this issue, put the input file as the first item in TPA.
830 ssTPAList.Append(pwzFilename);
833 // Are we compiling mscorlib.dll?
834 bool fCompilingMscorlib = StringEndsWith((LPWSTR)pwzFilename, CoreLibName_IL_W);
836 // Disable fragile NGen when compiling Mscorlib for ARM.
837 #if !(defined(_TARGET_ARM_) || defined(_TARGET_ARM64_))
838 if (fCompilingMscorlib)
839 dwFlags &= ~NGENWORKER_FLAGS_READYTORUN;
840 #endif // !(_TARGET_ARM_ || _TARGET_ARM64_)
842 if(pwzPlatformAssembliesPaths != nullptr)
844 // Platform_Assemblies_Paths command line switch has been specified.
845 _ASSERTE(pwzTrustedPlatformAssemblies == nullptr);
847 // Formulate the TPAList from Platform_Assemblies_Paths
848 ComputeTPAListFromPlatformAssembliesPath(pwzPlatformAssembliesPaths, ssTPAList, fCompilingMscorlib, fCreatePDB);
849 pwzTrustedPlatformAssemblies = (WCHAR *)ssTPAList.GetUnicode();
850 pwzPlatformAssembliesPaths = NULL;
853 if (pwzTrustedPlatformAssemblies != nullptr)
855 if (ComputeMscorlibPathFromTrustedPlatformAssemblies(wzTrustedPathRoot, pwzTrustedPlatformAssemblies))
857 pwzPlatformAssembliesPaths = wzTrustedPathRoot.GetUnicode();
858 SetMscorlibPath(pwzPlatformAssembliesPaths);
862 if (pwzPlatformAssembliesPaths == NULL)
864 if (!WszGetModuleFileName(NULL, wzTrustedPathRoot))
866 ERROR_WIN32(W("Error: GetModuleFileName failed (%d)\n"), GetLastError());
867 exit(CLR_INIT_ERROR);
870 if (SUCCEEDED(CopySystemDirectory(wzTrustedPathRoot, wzTrustedPathRoot)))
872 pwzPlatformAssembliesPaths = wzTrustedPathRoot.GetUnicode();
876 ERROR_HR(W("Error: wcsrchr returned NULL; GetModuleFileName must have given us something bad\n"), E_UNEXPECTED);
877 exit(CLR_INIT_ERROR);
883 // Initialize the logger
884 SetSvcLogger(&g_CrossgenLogger);
886 //Step - Compile the assembly
890 hr = CreatePDBWorker(
892 pwzPlatformAssembliesPaths,
893 pwzTrustedPlatformAssemblies,
894 pwzPlatformResourceRoots,
897 wzDirectoryToStorePDB,
898 fGeneratePDBLinesInfo,
899 pwzSearchPathForManagedPDB,
900 pwzPlatformWinmdPaths,
901 pwzDiasymreaderPath);
906 hr = NGenWorker(pwzFilename, dwFlags,
907 pwzPlatformAssembliesPaths,
908 pwzTrustedPlatformAssemblies,
909 pwzPlatformResourceRoots,
912 pwzPlatformWinmdPaths
913 #if !defined(FEATURE_MERGE_JIT_AND_ENGINE)
915 NULL, // ICorSvcLogger
917 #endif // !defined(FEATURE_MERGE_JIT_AND_ENGINE)
924 if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
926 OutputErrf(W("Error: file \"%s\" or one of its dependencies was not found\n"), pwzFilename);
927 exit(ASSEMBLY_NOT_FOUND);
931 OutputErrf(W("Error: compilation failed for \"%s\" (0x%08x)\n"), pwzFilename, hr);
940 int main(int argc, char *argv[])
942 if (0 != PAL_Initialize(argc, argv))
944 return FAILURE_RESULT;
947 wchar_t **wargv = new wchar_t*[argc];
948 for (int i = 0; i < argc; i++)
950 size_t len = strlen(argv[i]) + 1;
951 wargv[i] = new wchar_t[len];
952 WszMultiByteToWideChar(CP_ACP, 0, argv[i], -1, wargv[i], len);
955 int ret = wmain(argc, wargv);
957 for (int i = 0; i < argc; i++)
965 #endif // PLATFORM_UNIX