PageRenderTime 47ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Boo.Lang.Compiler/CompilerParameters.cs

https://github.com/boo/boo-lang
C# | 569 lines | 420 code | 91 blank | 58 comment | 51 complexity | ad08708f07cccd0fc96a6ba732cf5f40 MD5 | raw file
Possible License(s): GPL-2.0
  1. #region license
  2. // Copyright (c) 2004, Rodrigo B. de Oliveira (rbo@acm.org)
  3. // All rights reserved.
  4. //
  5. // Redistribution and use in source and binary forms, with or without modification,
  6. // are permitted provided that the following conditions are met:
  7. //
  8. // * Redistributions of source code must retain the above copyright notice,
  9. // this list of conditions and the following disclaimer.
  10. // * Redistributions in binary form must reproduce the above copyright notice,
  11. // this list of conditions and the following disclaimer in the documentation
  12. // and/or other materials provided with the distribution.
  13. // * Neither the name of Rodrigo B. de Oliveira nor the names of its
  14. // contributors may be used to endorse or promote products derived from this
  15. // software without specific prior written permission.
  16. //
  17. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  18. // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19. // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20. // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
  21. // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  23. // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  24. // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  25. // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26. // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. #endregion
  28. using System;
  29. using System.Collections;
  30. using System.Collections.Generic;
  31. using System.Diagnostics;
  32. using System.IO;
  33. using System.Reflection;
  34. using System.Text.RegularExpressions;
  35. namespace Boo.Lang.Compiler
  36. {
  37. /// <summary>
  38. /// Compiler parameters.
  39. /// </summary>
  40. public class CompilerParameters
  41. {
  42. private static List _validFileExtensions = new List(new string[] {".dll", ".exe"});
  43. private TextWriter _outputWriter;
  44. private CompilerPipeline _pipeline;
  45. private CompilerInputCollection _input;
  46. private CompilerResourceCollection _resources;
  47. private AssemblyCollection _assemblyReferences;
  48. private int _maxExpansionIterations;
  49. private string _outputAssembly;
  50. private CompilerOutputType _outputType;
  51. private bool _debug;
  52. private bool _ducky;
  53. private bool _checked;
  54. private bool _generateInMemory;
  55. private bool _StdLib;
  56. private string _keyFile;
  57. private string _keyContainer;
  58. private bool _delaySign;
  59. private ArrayList _libpaths;
  60. private string _systemDir;
  61. private Assembly _booAssembly;
  62. private bool _whiteSpaceAgnostic;
  63. private TraceSwitch _traceSwitch;
  64. private Dictionary<string, string> _defines = new Dictionary<string, string>();
  65. public CompilerParameters()
  66. : this(true)
  67. {
  68. }
  69. public CompilerParameters(bool loadDefaultReferences)
  70. {
  71. _libpaths = new ArrayList();
  72. _systemDir = GetSystemDir();
  73. _libpaths.Add(_systemDir);
  74. _libpaths.Add(Directory.GetCurrentDirectory());
  75. _pipeline = null;
  76. _input = new CompilerInputCollection();
  77. _resources = new CompilerResourceCollection();
  78. _assemblyReferences = new AssemblyCollection();
  79. _maxExpansionIterations = 4;
  80. _outputAssembly = string.Empty;
  81. _outputType = CompilerOutputType.ConsoleApplication;
  82. _outputWriter = System.Console.Out;
  83. _debug = true;
  84. _checked = true;
  85. _generateInMemory = true;
  86. _StdLib = true;
  87. if (null != Environment.GetEnvironmentVariable("TRACE"))
  88. EnableTraceSwitch();
  89. _delaySign = false;
  90. if (loadDefaultReferences) LoadDefaultReferences();
  91. }
  92. public void LoadDefaultReferences()
  93. {
  94. //mscorlib
  95. _assemblyReferences.Add(
  96. LoadAssembly("mscorlib", true)
  97. );
  98. //System
  99. _assemblyReferences.Add(
  100. LoadAssembly("System", true)
  101. );
  102. //boo.lang.dll
  103. _booAssembly = typeof(Boo.Lang.Builtins).Assembly;
  104. _assemblyReferences.Add(_booAssembly);
  105. //boo.lang.extensions.dll
  106. //try loading extensions next to Boo.Lang (in the same directory)
  107. string tentative = Path.Combine(Path.GetDirectoryName(_booAssembly.Location) , "Boo.Lang.Extensions.dll");
  108. Assembly extensionsAssembly = LoadAssembly(tentative, false);
  109. if(extensionsAssembly == null)//if failed, try loading from the gac
  110. extensionsAssembly = LoadAssembly("Boo.Lang.Extensions", false);
  111. if(extensionsAssembly != null)
  112. _assemblyReferences.Add(extensionsAssembly);
  113. if (TraceInfo)
  114. {
  115. Trace.WriteLine("BOO LANG DLL: " + _booAssembly.Location);
  116. Trace.WriteLine("BOO COMPILER EXTENSIONS DLL: " +
  117. (extensionsAssembly != null ? extensionsAssembly.Location : "NOT FOUND!"));
  118. }
  119. }
  120. public Assembly BooAssembly
  121. {
  122. get { return _booAssembly; }
  123. set
  124. {
  125. if (value != null)
  126. {
  127. (_assemblyReferences as IList).Remove(_booAssembly);
  128. _booAssembly = value;
  129. _assemblyReferences.Add(value);
  130. }
  131. }
  132. }
  133. public Assembly FindAssembly(string name)
  134. {
  135. return _assemblyReferences.Find(name);
  136. }
  137. public void AddAssembly(Assembly asm)
  138. {
  139. if (asm != null)
  140. {
  141. _assemblyReferences.Add(asm);
  142. }
  143. }
  144. public Assembly LoadAssembly(string assembly)
  145. {
  146. return LoadAssembly(assembly, true);
  147. }
  148. public Assembly LoadAssembly(string assembly, bool throwOnError)
  149. {
  150. if (TraceInfo)
  151. {
  152. Trace.WriteLine("ATTEMPTING LOADASSEMBLY: " + assembly);
  153. }
  154. Assembly a = null;
  155. try
  156. {
  157. if (assembly.IndexOfAny(new char[] {'/', '\\'}) != -1)
  158. {
  159. //nant passes full path to gac dlls, which compiler doesn't like:
  160. //if (assembly.ToLower().StartsWith(_systemDir.ToLower()))
  161. {
  162. //return LoadAssemblyFromGac(Path.GetFileName(assembly));
  163. }
  164. //else //load using path
  165. {
  166. a = Assembly.LoadFrom(assembly);
  167. }
  168. }
  169. else
  170. {
  171. a = LoadAssemblyFromGac(assembly);
  172. }
  173. }
  174. catch (FileNotFoundException /*ignored*/)
  175. {
  176. return LoadAssemblyFromLibPaths(assembly, throwOnError);
  177. }
  178. catch (BadImageFormatException e)
  179. {
  180. if (throwOnError)
  181. {
  182. throw new ApplicationException(Boo.Lang.ResourceManager.Format(
  183. "BooC.BadFormat",
  184. e.FusionLog), e);
  185. }
  186. }
  187. catch (FileLoadException e)
  188. {
  189. if (throwOnError)
  190. {
  191. throw new ApplicationException(Boo.Lang.ResourceManager.Format(
  192. "BooC.UnableToLoadAssembly",
  193. e.FusionLog), e);
  194. }
  195. }
  196. catch (ArgumentNullException e)
  197. {
  198. if (throwOnError)
  199. {
  200. throw new ApplicationException(Boo.Lang.ResourceManager.Format(
  201. "BooC.NullAssembly"), e);
  202. }
  203. }
  204. if (a == null)
  205. {
  206. return LoadAssemblyFromLibPaths(assembly, throwOnError);
  207. }
  208. return a;
  209. }
  210. private Assembly LoadAssemblyFromLibPaths(string assembly, bool throwOnError)
  211. {
  212. Assembly a = null;
  213. string fullLog = "";
  214. foreach (string dir in _libpaths)
  215. {
  216. string full_path = Path.Combine(dir, assembly);
  217. FileInfo file = new FileInfo(full_path);
  218. if (!_validFileExtensions.Contains(file.Extension.ToLower()))
  219. full_path += ".dll";
  220. try
  221. {
  222. a = Assembly.LoadFrom(full_path);
  223. if (a != null)
  224. {
  225. return a;
  226. }
  227. }
  228. catch (FileNotFoundException ff)
  229. {
  230. fullLog += ff.FusionLog;
  231. continue;
  232. }
  233. }
  234. if (throwOnError)
  235. {
  236. throw new ApplicationException(Boo.Lang.ResourceManager.Format(
  237. "BooC.CannotFindAssembly",
  238. assembly));
  239. //assembly, total_log)); //total_log contains the fusion log
  240. }
  241. return a;
  242. }
  243. private Assembly LoadAssemblyFromGac(string assemblyName)
  244. {
  245. assemblyName = NormalizeAssemblyName(assemblyName);
  246. // This is an intentional attempt to load an assembly with partial name
  247. // so ignore the compiler warning
  248. #pragma warning disable 618
  249. Assembly assembly = Assembly.LoadWithPartialName(assemblyName);
  250. #pragma warning restore 618
  251. if (assembly != null) return assembly;
  252. return Assembly.Load(assemblyName);
  253. }
  254. private static string NormalizeAssemblyName(string assembly)
  255. {
  256. if (assembly.EndsWith(".dll") || assembly.EndsWith(".exe"))
  257. {
  258. assembly = assembly.Substring(0, assembly.Length - 4);
  259. }
  260. return assembly;
  261. }
  262. public void LoadReferencesFromPackage(string package)
  263. {
  264. string[] libs = Regex.Split(pkgconfig(package), @"\-r\:", RegexOptions.CultureInvariant);
  265. foreach (string r in libs)
  266. {
  267. string reference = r.Trim();
  268. if (reference.Length == 0) continue;
  269. Trace.WriteLine("LOADING REFERENCE FROM PKGCONFIG '" + package + "' : " + reference);
  270. References.Add(LoadAssembly(reference));
  271. }
  272. }
  273. private static string pkgconfig(string package)
  274. {
  275. #if NO_SYSTEM_DLL
  276. throw new System.NotSupportedException();
  277. #else
  278. Process process;
  279. try
  280. {
  281. process = Builtins.shellp("pkg-config", string.Format("--libs {0}", package));
  282. }
  283. catch (Exception e)
  284. {
  285. throw new ApplicationException(Boo.Lang.ResourceManager.GetString("BooC.PkgConfigNotFound"), e);
  286. }
  287. process.WaitForExit();
  288. if (process.ExitCode != 0)
  289. {
  290. throw new ApplicationException(
  291. Boo.Lang.ResourceManager.Format("BooC.PkgConfigReportedErrors", process.StandardError.ReadToEnd()));
  292. }
  293. return process.StandardOutput.ReadToEnd();
  294. #endif
  295. }
  296. private string GetSystemDir()
  297. {
  298. return Path.GetDirectoryName(typeof(string).Assembly.Location);
  299. }
  300. /// <summary>
  301. /// Max number of iterations for the application of AST attributes and the
  302. /// expansion of macros.
  303. /// </summary>
  304. public int MaxExpansionIterations
  305. {
  306. get { return _maxExpansionIterations; }
  307. set { _maxExpansionIterations = value; }
  308. }
  309. public CompilerInputCollection Input
  310. {
  311. get { return _input; }
  312. }
  313. public ArrayList LibPaths
  314. {
  315. get { return _libpaths; }
  316. }
  317. public CompilerResourceCollection Resources
  318. {
  319. get { return _resources; }
  320. }
  321. public AssemblyCollection References
  322. {
  323. get { return _assemblyReferences; }
  324. set
  325. {
  326. if (null == value) throw new ArgumentNullException("References");
  327. _assemblyReferences = value;
  328. }
  329. }
  330. /// <summary>
  331. /// The compilation pipeline.
  332. /// </summary>
  333. public CompilerPipeline Pipeline
  334. {
  335. get { return _pipeline; }
  336. set { _pipeline = value; }
  337. }
  338. /// <summary>
  339. /// The name (full or partial) for the file
  340. /// that should receive the resulting assembly.
  341. /// </summary>
  342. public string OutputAssembly
  343. {
  344. get { return _outputAssembly; }
  345. set
  346. {
  347. if (string.IsNullOrEmpty(value)) throw new ArgumentNullException("OutputAssembly");
  348. _outputAssembly = value;
  349. }
  350. }
  351. /// <summary>
  352. /// Type and execution subsystem for the generated portable
  353. /// executable file.
  354. /// </summary>
  355. public CompilerOutputType OutputType
  356. {
  357. get { return _outputType; }
  358. set { _outputType = value; }
  359. }
  360. public bool GenerateInMemory
  361. {
  362. get { return _generateInMemory; }
  363. set { _generateInMemory = value; }
  364. }
  365. public bool StdLib
  366. {
  367. get { return _StdLib; }
  368. set { _StdLib = value; }
  369. }
  370. public TextWriter OutputWriter
  371. {
  372. get { return _outputWriter; }
  373. set
  374. {
  375. if (null == value)
  376. {
  377. throw new ArgumentNullException("OutputWriter");
  378. }
  379. _outputWriter = value;
  380. }
  381. }
  382. public bool Debug
  383. {
  384. get { return _debug; }
  385. set { _debug = value; }
  386. }
  387. /// <summary>
  388. /// Use duck instead of object as the most generic type.
  389. /// </summary>
  390. public bool Ducky
  391. {
  392. get { return _ducky; }
  393. set { _ducky = value; }
  394. }
  395. public bool Checked
  396. {
  397. get { return _checked; }
  398. set { _checked = value; }
  399. }
  400. public string KeyFile
  401. {
  402. get { return _keyFile; }
  403. set { _keyFile = value; }
  404. }
  405. public string KeyContainer
  406. {
  407. get { return _keyContainer; }
  408. set { _keyContainer = value; }
  409. }
  410. public bool DelaySign
  411. {
  412. get { return _delaySign; }
  413. set { _delaySign = value; }
  414. }
  415. public bool WhiteSpaceAgnostic
  416. {
  417. get
  418. {
  419. return _whiteSpaceAgnostic;
  420. }
  421. set
  422. {
  423. _whiteSpaceAgnostic = value;
  424. }
  425. }
  426. public Dictionary<string, string> Defines
  427. {
  428. get
  429. {
  430. return _defines;
  431. }
  432. }
  433. internal TraceSwitch TraceSwitch
  434. {
  435. get
  436. {
  437. return _traceSwitch;
  438. }
  439. set
  440. {
  441. if (null == _traceSwitch)
  442. _traceSwitch = value;
  443. }
  444. }
  445. public bool TraceInfo
  446. {
  447. get { return (null != _traceSwitch && _traceSwitch.TraceInfo); }
  448. }
  449. public bool TraceWarning
  450. {
  451. get { return (null != _traceSwitch && _traceSwitch.TraceWarning); }
  452. }
  453. public bool TraceError
  454. {
  455. get { return (null != _traceSwitch && _traceSwitch.TraceError); }
  456. }
  457. public bool TraceVerbose
  458. {
  459. get { return (null != _traceSwitch && _traceSwitch.TraceVerbose); }
  460. }
  461. public TraceLevel TraceLevel
  462. {
  463. get {
  464. return (null != _traceSwitch)
  465. ? _traceSwitch.Level : TraceLevel.Off;
  466. }
  467. set {
  468. EnableTraceSwitch();
  469. _traceSwitch.Level = value;
  470. }
  471. }
  472. public void EnableTraceSwitch()
  473. {
  474. if (null == _traceSwitch)
  475. _traceSwitch = new TraceSwitch("booc", "boo compiler");
  476. }
  477. }
  478. }