Config.pm 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  1. # ------------------------------------------------------------------------------
  2. # NAME
  3. # Fcm::Config
  4. #
  5. # DESCRIPTION
  6. # This is a class for reading and processing central and user configuration
  7. # settings for FCM.
  8. #
  9. # COPYRIGHT
  10. # (C) Crown copyright Met Office. All rights reserved.
  11. # For further details please refer to the file COPYRIGHT.txt
  12. # which you should have received as part of this distribution.
  13. # ------------------------------------------------------------------------------
  14. package Fcm::Config;
  15. # Standard pragma
  16. use warnings;
  17. use strict;
  18. # Standard modules
  19. use File::Basename;
  20. use File::Spec::Functions;
  21. use FindBin;
  22. use POSIX qw/setlocale LC_ALL/;
  23. # FCM component modules
  24. use Fcm::CfgFile;
  25. # Other declarations:
  26. sub _get_hash_value;
  27. # Delimiter for setting and for list
  28. our $DELIMITER = '::';
  29. our $DELIMITER_PATTERN = qr{::|/};
  30. our $DELIMITER_LIST = ',';
  31. my $INSTANCE;
  32. # ------------------------------------------------------------------------------
  33. # SYNOPSIS
  34. # $config = Fcm::Config->instance();
  35. #
  36. # DESCRIPTION
  37. # Returns an instance of this class.
  38. # ------------------------------------------------------------------------------
  39. sub instance {
  40. my ($class) = @_;
  41. if (!defined($INSTANCE)) {
  42. $INSTANCE = $class->new();
  43. $INSTANCE->get_config();
  44. $INSTANCE->is_initialising(0);
  45. }
  46. return $INSTANCE;
  47. }
  48. # ------------------------------------------------------------------------------
  49. # SYNOPSIS
  50. # $obj = Fcm::Config->new (VERBOSE => $verbose);
  51. #
  52. # DESCRIPTION
  53. # This method constructs a new instance of the Fcm::Config class.
  54. #
  55. # ARGUMENTS
  56. # VERBOSE - Set the verbose level of diagnostic output
  57. # ------------------------------------------------------------------------------
  58. sub new {
  59. my $this = shift;
  60. my %args = @_;
  61. my $class = ref $this || $this;
  62. # Ensure that all subsequent Subversion output is in UK English
  63. if (setlocale (LC_ALL, 'en_GB')) {
  64. $ENV{LANG} = 'en_GB';
  65. }
  66. my $self = {
  67. initialising => 1,
  68. central_config => undef,
  69. user_config => undef,
  70. user_id => undef,
  71. verbose => exists $args{VERBOSE} ? $args{VERBOSE} : undef,
  72. variable => {},
  73. # Primary settings
  74. setting => {
  75. # Current command
  76. FCM_COMMAND => &basename ($0),
  77. # Current FCM release identifier
  78. FCM_RELEASE => '1-5',
  79. # Location of file with the last changed revision of the FCM trunk
  80. FCM_REV_FILE => catfile (dirname ($FindBin::Bin), 'etc', 'fcm_rev'),
  81. # Fortran BLOCKDATA dependencies
  82. BLD_BLOCKDATA => {},
  83. # Copy dummy target
  84. BLD_CPDUMMY => '$(FCM_DONEDIR)/FCM_CP.dummy',
  85. # No dependency check
  86. BLD_DEP_N => {},
  87. # Additional (PP) dependencies
  88. BLD_DEP => {},
  89. BLD_DEP_PP => {},
  90. # Excluded dependency
  91. BLD_DEP_EXCL => {
  92. '' => [
  93. # Fortran intrinsic modules
  94. 'USE' . $DELIMITER . 'ISO_C_BINDING',
  95. 'USE' . $DELIMITER . 'IEEE_EXCEPTIONS',
  96. 'USE' . $DELIMITER . 'IEEE_ARITHMETIC',
  97. 'USE' . $DELIMITER . 'IEEE_FEATURES',
  98. # Fortran intrinsic subroutines
  99. 'OBJ' . $DELIMITER . 'CPU_TIME',
  100. 'OBJ' . $DELIMITER . 'GET_COMMAND',
  101. 'OBJ' . $DELIMITER . 'GET_COMMAND_ARGUMENT',
  102. 'OBJ' . $DELIMITER . 'GET_ENVIRONMENT_VARIABLE',
  103. 'OBJ' . $DELIMITER . 'MOVE_ALLOC',
  104. 'OBJ' . $DELIMITER . 'MVBITS',
  105. 'OBJ' . $DELIMITER . 'RANDOM_NUMBER',
  106. 'OBJ' . $DELIMITER . 'RANDOM_SEED',
  107. 'OBJ' . $DELIMITER . 'SYSTEM_CLOCK',
  108. # Dummy statements
  109. 'OBJ' . $DELIMITER . 'NONE',
  110. 'EXE' . $DELIMITER . 'NONE',
  111. ],
  112. },
  113. # Extra executable dependencies
  114. BLD_DEP_EXE => {},
  115. # Dependency pattern for each type
  116. BLD_DEP_PATTERN => {
  117. H => q/^#\s*include\s*['"](\S+)['"]/,
  118. USE => q/^\s*use\s+(\w+)/,
  119. INTERFACE => q/^#?\s*include\s+['"](\S+##OUTFILE_EXT/ . $DELIMITER .
  120. q/INTERFACE##)['"]/,
  121. INC => q/^\s*include\s+['"](\S+)['"]/,
  122. OBJ => q#^\s*(?:/\*|!)\s*depends\s*on\s*:\s*(\S+)#,
  123. EXE => q/^\s*(?:#|;)\s*(?:calls|list|if|interface)\s*:\s*(\S+)/,
  124. },
  125. # Rename main program targets
  126. BLD_EXE_NAME => {},
  127. # Rename library targets
  128. BLD_LIB => {'' => 'fcm_default'},
  129. # Name of Makefile and run environment shell script
  130. BLD_MISC => {
  131. 'BLDMAKEFILE' => 'Makefile',
  132. 'BLDRUNENVSH' => 'fcm_env.sh',
  133. },
  134. # PP flags
  135. BLD_PP => {},
  136. # Custom source file type
  137. BLD_TYPE => {},
  138. # Types that always need to be built
  139. BLD_TYPE_ALWAYS_BUILD => 'PVWAVE' .
  140. $DELIMITER_LIST . 'GENLIST' .
  141. $DELIMITER_LIST . 'SQL',
  142. # Dependency scan types
  143. BLD_TYPE_DEP => {
  144. FORTRAN => 'USE' .
  145. $DELIMITER . 'INTERFACE' .
  146. $DELIMITER . 'INC' .
  147. $DELIMITER . 'OBJ',
  148. FPP => 'USE' .
  149. $DELIMITER . 'INTERFACE' .
  150. $DELIMITER . 'INC' .
  151. $DELIMITER . 'H' .
  152. $DELIMITER . 'OBJ',
  153. CPP => 'H' .
  154. $DELIMITER . 'OBJ',
  155. C => 'H' .
  156. $DELIMITER . 'OBJ',
  157. SCRIPT => 'EXE',
  158. },
  159. # Dependency scan types for pre-processing
  160. BLD_TYPE_DEP_PP => {
  161. FPP => 'H',
  162. CPP => 'H',
  163. C => 'H',
  164. },
  165. # Types that cannot have duplicated targets
  166. BLD_TYPE_NO_DUPLICATED_TARGET => '',
  167. # BLD_VPATH, each value must be a comma separate list
  168. # '' translates to %
  169. # 'FLAG' translates to {OUTFILE_EXT}{FLAG}
  170. BLD_VPATH => {
  171. BIN => q{},
  172. ETC => 'ETC',
  173. DONE => join($DELIMITER_LIST, qw{DONE IDONE}),
  174. FLAGS => 'FLAGS',
  175. INC => q{},
  176. LIB => 'LIB',
  177. OBJ => 'OBJ',
  178. },
  179. # Cache basename
  180. CACHE => '.config',
  181. CACHE_DEP => '.config_dep',
  182. CACHE_DEP_PP => '.config_dep_pp',
  183. CACHE_FILE_SRC => '.config_file_src',
  184. # Types of "inc" statements expandable CFG files
  185. CFG_EXP_INC => 'BLD' .
  186. $DELIMITER_LIST . 'EXT' .
  187. $DELIMITER_LIST . 'FCM',
  188. # Configuration file labels that can be declared more than once
  189. CFG_KEYWORD => 'USE' .
  190. $DELIMITER_LIST . 'INC' .
  191. $DELIMITER_LIST . 'TARGET' .
  192. $DELIMITER_LIST . 'BLD_DEP_EXCL',
  193. # Labels for all types of FCM configuration files
  194. CFG_LABEL => {
  195. CFGFILE => 'CFG', # config file information
  196. INC => 'INC', # "include" from an configuration file
  197. # Labels for central/user internal config setting
  198. SETTING => 'SET',
  199. # Labels for systems that allow inheritance
  200. DEST => 'DEST', # destination
  201. USE => 'USE', # use (inherit) a previous configuration
  202. # Labels for bld and pck cfg
  203. TARGET => 'TARGET', # BLD: declare targets, PCK: target of source file
  204. # Labels for bld cfg
  205. BLD_BLOCKDATA => 'BLOCKDATA', # declare Fortran BLOCKDATA dependencies
  206. BLD_DEP => 'DEP', # additional dependencies
  207. BLD_DEP_N => 'NO_DEP', # no dependency check
  208. BLD_DEP_EXCL => 'EXCL_DEP', # exclude automatic dependencies
  209. BLD_DEP_EXE => 'EXE_DEP', # declare dependencies for program
  210. BLD_EXE_NAME => 'EXE_NAME', # rename a main program
  211. BLD_LIB => 'LIB', # rename library
  212. BLD_PP => 'PP', # sub-package needs pre-process?
  213. BLD_TYPE => 'SRC_TYPE', # custom source file type
  214. DIR => 'DIR', # DEPRECATED, same as DEST
  215. INFILE_EXT => 'INFILE_EXT', # change input file name extension type
  216. INHERIT => 'INHERIT', # inheritance flag
  217. NAME => 'NAME', # name the build
  218. OUTFILE_EXT => 'OUTFILE_EXT', # change output file type extension
  219. FILE => 'SRC', # declare a sub-package
  220. SEARCH_SRC => 'SEARCH_SRC', # search src/ sub-directory?
  221. TOOL => 'TOOL', # declare a tool
  222. # Labels for ext cfg
  223. BDECLARE => 'BLD', # build declaration
  224. CONFLICT => 'CONFLICT', # set conflict mode
  225. DIRS => 'SRC', # declare source directory
  226. EXPDIRS => 'EXPSRC', # declare expandable source directory
  227. MIRROR => 'MIRROR', # DEPRECATED, same as RDEST::MIRROR_CMD
  228. OVERRIDE => 'OVERRIDE', # DEPRECATED, replaced by CONFLICT
  229. RDEST => 'RDEST', # declare remote destionation
  230. REVISION => 'REVISION', # declare branch revision in a project
  231. REVMATCH => 'REVMATCH', # branch revision must match changed revision
  232. REPOS => 'REPOS', # declare branch in a project
  233. VERSION => 'VERSION', # DEPRECATED, same as REVISION
  234. },
  235. # Default names of known FCM configuration files
  236. CFG_NAME => {
  237. BLD => 'bld.cfg', # build configuration file
  238. EXT => 'ext.cfg', # extract configuration file
  239. PARSED => 'parsed_', # as-parsed configuration file prefix
  240. },
  241. # Latest version of known FCM configuration files
  242. CFG_VERSION => {
  243. BLD => '1.0', # bld cfg
  244. EXT => '1.0', # ext cfg
  245. },
  246. # Standard sub-directories for extract/build
  247. DIR => {
  248. BIN => 'bin', # executable
  249. BLD => 'bld', # build
  250. CACHE => '.cache', # cache
  251. CFG => 'cfg', # configuration
  252. DONE => 'done', # "done"
  253. ETC => 'etc', # miscellaneous items
  254. FLAGS => 'flags', # "flags"
  255. INC => 'inc', # include
  256. LIB => 'lib', # library
  257. OBJ => 'obj', # object
  258. PPSRC => 'ppsrc', # pre-processed source
  259. SRC => 'src', # source
  260. TMP => 'tmp', # temporary directory
  261. },
  262. # A flag to indicate whether the revision of a given branch for extract
  263. # must match with the revision of a changed revision of the branch
  264. EXT_REVMATCH => 0, # default is false (allow any revision)
  265. # Input file name extension and type
  266. # (may overlap with output (below) and vpath (above))
  267. INFILE_EXT => {
  268. # General extensions
  269. 'f' => 'FORTRAN' .
  270. $DELIMITER . 'SOURCE',
  271. 'for' => 'FORTRAN' .
  272. $DELIMITER . 'SOURCE',
  273. 'ftn' => 'FORTRAN' .
  274. $DELIMITER . 'SOURCE',
  275. 'f77' => 'FORTRAN' .
  276. $DELIMITER . 'SOURCE',
  277. 'f90' => 'FORTRAN' .
  278. $DELIMITER . 'FORTRAN9X' .
  279. $DELIMITER . 'SOURCE',
  280. 'f95' => 'FORTRAN' .
  281. $DELIMITER . 'FORTRAN9X' .
  282. $DELIMITER . 'SOURCE',
  283. 'F' => 'FPP' .
  284. $DELIMITER . 'SOURCE',
  285. 'FOR' => 'FPP' .
  286. $DELIMITER . 'SOURCE',
  287. 'FTN' => 'FPP' .
  288. $DELIMITER . 'SOURCE',
  289. 'F77' => 'FPP' .
  290. $DELIMITER . 'SOURCE',
  291. 'F90' => 'FPP' .
  292. $DELIMITER . 'FPP9X' .
  293. $DELIMITER . 'SOURCE',
  294. 'F95' => 'FPP' .
  295. $DELIMITER . 'FPP9X' .
  296. $DELIMITER . 'SOURCE',
  297. 'c' => 'C' .
  298. $DELIMITER . 'SOURCE',
  299. 'cpp' => 'C' .
  300. $DELIMITER . 'C++' .
  301. $DELIMITER . 'SOURCE',
  302. 'h' => 'CPP' .
  303. $DELIMITER . 'INCLUDE',
  304. 'o' => 'BINARY' .
  305. $DELIMITER . 'OBJ',
  306. 'obj' => 'BINARY' .
  307. $DELIMITER . 'OBJ',
  308. 'exe' => 'BINARY' .
  309. $DELIMITER . 'EXE',
  310. 'a' => 'BINARY' .
  311. $DELIMITER . 'LIB',
  312. 'sh' => 'SCRIPT' .
  313. $DELIMITER . 'SHELL',
  314. 'ksh' => 'SCRIPT' .
  315. $DELIMITER . 'SHELL',
  316. 'bash' => 'SCRIPT' .
  317. $DELIMITER . 'SHELL',
  318. 'csh' => 'SCRIPT' .
  319. $DELIMITER . 'SHELL',
  320. 'pl' => 'SCRIPT' .
  321. $DELIMITER . 'PERL',
  322. 'pm' => 'SCRIPT' .
  323. $DELIMITER . 'PERL',
  324. 'py' => 'SCRIPT' .
  325. $DELIMITER . 'PYTHON',
  326. 'tcl' => 'SCRIPT' .
  327. $DELIMITER . 'TCL',
  328. 'pro' => 'SCRIPT' .
  329. $DELIMITER . 'PVWAVE',
  330. # Local extensions
  331. 'cfg' => 'CFGFILE',
  332. 'h90' => 'CPP' .
  333. $DELIMITER . 'INCLUDE',
  334. 'inc' => 'FORTRAN' .
  335. $DELIMITER . 'FORTRAN9X' .
  336. $DELIMITER . 'INCLUDE',
  337. 'interface' => 'FORTRAN' .
  338. $DELIMITER . 'FORTRAN9X' .
  339. $DELIMITER . 'INCLUDE' .
  340. $DELIMITER . 'INTERFACE',
  341. },
  342. # Ignore input files matching the following names (comma-separated list)
  343. INFILE_IGNORE => 'fcm_env.ksh' .
  344. $DELIMITER_LIST . 'fcm_env.sh',
  345. # Input file name pattern and type
  346. INFILE_PAT => {
  347. '\w+Scr_\w+' => 'SCRIPT' .
  348. $DELIMITER . 'SHELL',
  349. '\w+Comp_\w+' => 'SCRIPT' .
  350. $DELIMITER . 'SHELL' .
  351. $DELIMITER . 'GENTASK',
  352. '\w+(?:IF|Interface)_\w+' => 'SCRIPT' .
  353. $DELIMITER . 'SHELL' .
  354. $DELIMITER . 'GENIF',
  355. '\w+Suite_\w+' => 'SCRIPT' .
  356. $DELIMITER . 'SHELL' .
  357. $DELIMITER . 'GENSUITE',
  358. '\w+List_\w+' => 'SCRIPT' .
  359. $DELIMITER . 'SHELL' .
  360. $DELIMITER . 'GENLIST',
  361. '\w+Sql_\w+' => 'SCRIPT' .
  362. $DELIMITER . 'SQL',
  363. },
  364. # Input text file pattern and type
  365. INFILE_TXT => {
  366. '(?:[ck]|ba)?sh' => 'SCRIPT' .
  367. $DELIMITER . 'SHELL',
  368. 'perl' => 'SCRIPT' .
  369. $DELIMITER . 'PERL',
  370. 'python' => 'SCRIPT' .
  371. $DELIMITER . 'PYTHON',
  372. 'tcl(?:sh)?|wish' => 'SCRIPT' .
  373. $DELIMITER . 'TCL',
  374. },
  375. # Lock file
  376. LOCK => {
  377. BLDLOCK => 'fcm.bld.lock', # build lock file
  378. EXTLOCK => 'fcm.ext.lock', # extract lock file
  379. },
  380. # Output file type and extension
  381. # (may overlap with input and vpath (above))
  382. OUTFILE_EXT => {
  383. CFG => '.cfg', # FCM configuration file
  384. DONE => '.done', # "done" files for compiled source
  385. ETC => '.etc', # "etc" dummy file
  386. EXE => '.exe', # binary executables
  387. FLAGS => '.flags', # "flags" files, compiler flags config
  388. IDONE => '.idone', # "done" files for included source
  389. INTERFACE => '.interface', # interface for F90 subroutines/functions
  390. LIB => '.a', # archive object library
  391. MOD => '.mod', # compiled Fortran module information files
  392. OBJ => '.o', # compiled object files
  393. PDONE => '.pdone', # "done" files for pre-processed files
  394. TAR => '.tar', # TAR archive
  395. },
  396. # Build commands and options (i.e. tools)
  397. TOOL => {
  398. SHELL => '/bin/sh', # Default shell
  399. CPP => 'cpp', # C pre-processor
  400. CPPFLAGS => '-C', # CPP flags
  401. CPP_INCLUDE => '-I', # CPP flag, specify "include" path
  402. CPP_DEFINE => '-D', # CPP flag, define macro
  403. CPPKEYS => '', # CPP keys (definition macro)
  404. CC => 'cc', # C compiler
  405. CFLAGS => '', # CC flags
  406. CC_COMPILE => '-c', # CC flag, compile only
  407. CC_OUTPUT => '-o', # CC flag, specify output file name
  408. CC_INCLUDE => '-I', # CC flag, specify "include" path
  409. CC_DEFINE => '-D', # CC flag, define macro
  410. FPP => 'cpp', # Fortran pre-processor
  411. FPPFLAGS => '-P -traditional', # FPP flags
  412. FPP_INCLUDE => '-I', # FPP flag, specify "include" path
  413. FPP_DEFINE => '-D', # FPP flag, define macro
  414. FPPKEYS => '', # FPP keys (definition macro)
  415. FC => 'f90', # Fortran compiler
  416. FFLAGS => '', # FC flags
  417. FC_COMPILE => '-c', # FC flag, compile only
  418. FC_OUTPUT => '-o', # FC flag, specify output file name
  419. FC_INCLUDE => '-I', # FC flag, specify "include" path
  420. FC_MODSEARCH => '', # FC flag, specify "module" path
  421. FC_DEFINE => '-D', # FC flag, define macro
  422. LD => '', # linker
  423. LDFLAGS => '', # LD flags
  424. LD_OUTPUT => '-o', # LD flag, specify output file name
  425. LD_LIBSEARCH => '-L', # LD flag, specify "library" path
  426. LD_LIBLINK => '-l', # LD flag, specify link library
  427. AR => 'ar', # library archiver
  428. ARFLAGS => 'rs', # AR flags
  429. MAKE => 'make', # make command
  430. MAKEFLAGS => '', # make flags
  431. MAKE_FILE => '-f', # make flag, path to Makefile
  432. MAKE_SILENT => '-s', # make flag, silent diagnostic
  433. MAKE_JOB => '-j', # make flag, number of jobs
  434. INTERFACE => 'file', # name interface after file/program
  435. GENINTERFACE => '', # Fortran 9x interface generator
  436. DIFF3 => 'diff3', # extract diff3 merge
  437. DIFF3FLAGS => '-E -m', # DIFF3 flags
  438. GRAPHIC_DIFF => 'xxdiff', # graphical diff tool
  439. GRAPHIC_MERGE=> 'xxdiff', # graphical merge tool
  440. },
  441. # List of tools that are local to FCM, (will not be exported to a Makefile)
  442. TOOL_LOCAL => 'CPP' .
  443. $DELIMITER_LIST . 'CPPFLAGS' .
  444. $DELIMITER_LIST . 'CPP_INCLUDE' .
  445. $DELIMITER_LIST . 'CPP_DEFINE' .
  446. $DELIMITER_LIST . 'DIFF3' .
  447. $DELIMITER_LIST . 'DIFF3_FLAGS' .
  448. $DELIMITER_LIST . 'FPP' .
  449. $DELIMITER_LIST . 'FPPFLAGS' .
  450. $DELIMITER_LIST . 'FPP_INCLUDE' .
  451. $DELIMITER_LIST . 'FPP_DEFINE' .
  452. $DELIMITER_LIST . 'GRAPHIC_DIFF' .
  453. $DELIMITER_LIST . 'GRAPHIC_MERGE' .
  454. $DELIMITER_LIST . 'MAKE' .
  455. $DELIMITER_LIST . 'MAKEFLAGS' .
  456. $DELIMITER_LIST . 'MAKE_FILE' .
  457. $DELIMITER_LIST . 'MAKE_SILENT' .
  458. $DELIMITER_LIST . 'MAKE_JOB' .
  459. $DELIMITER_LIST . 'INTERFACE' .
  460. $DELIMITER_LIST . 'GENINTERFACE' .
  461. $DELIMITER_LIST . 'MIRROR' .
  462. $DELIMITER_LIST . 'REMOTE_SHELL',
  463. # List of tools that allow sub-package declarations
  464. TOOL_PACKAGE => 'CPPFLAGS' .
  465. $DELIMITER_LIST . 'CPPKEYS' .
  466. $DELIMITER_LIST . 'CFLAGS' .
  467. $DELIMITER_LIST . 'FPPFLAGS' .
  468. $DELIMITER_LIST . 'FPPKEYS' .
  469. $DELIMITER_LIST . 'FFLAGS' .
  470. $DELIMITER_LIST . 'LD' .
  471. $DELIMITER_LIST . 'LDFLAGS' .
  472. $DELIMITER_LIST . 'INTERFACE' .
  473. $DELIMITER_LIST . 'GENINTERFACE',
  474. # Supported tools for compilable source
  475. TOOL_SRC_PP => {
  476. FPP => {
  477. COMMAND => 'FPP',
  478. FLAGS => 'FPPFLAGS',
  479. PPKEYS => 'FPPKEYS',
  480. INCLUDE => 'FPP_INCLUDE',
  481. DEFINE => 'FPP_DEFINE',
  482. },
  483. C => {
  484. COMMAND => 'CPP',
  485. FLAGS => 'CPPFLAGS',
  486. PPKEYS => 'CPPKEYS',
  487. INCLUDE => 'CPP_INCLUDE',
  488. DEFINE => 'CPP_DEFINE',
  489. },
  490. },
  491. # Supported tools for compilable source
  492. TOOL_SRC => {
  493. FORTRAN => {
  494. COMMAND => 'FC',
  495. FLAGS => 'FFLAGS',
  496. OUTPUT => 'FC_OUTPUT',
  497. INCLUDE => 'FC_INCLUDE',
  498. },
  499. FPP => {
  500. COMMAND => 'FC',
  501. FLAGS => 'FFLAGS',
  502. PPKEYS => 'FPPKEYS',
  503. OUTPUT => 'FC_OUTPUT',
  504. INCLUDE => 'FC_INCLUDE',
  505. DEFINE => 'FC_DEFINE',
  506. },
  507. C => {
  508. COMMAND => 'CC',
  509. FLAGS => 'CFLAGS',
  510. PPKEYS => 'CPPKEYS',
  511. OUTPUT => 'CC_OUTPUT',
  512. INCLUDE => 'CC_INCLUDE',
  513. DEFINE => 'CC_DEFINE',
  514. },
  515. },
  516. # FCM URL keyword and prefix, FCM revision keyword, and FCM Trac URL
  517. URL => {},
  518. URL_REVISION => {},
  519. URL_BROWSER_MAPPING => {},
  520. URL_BROWSER_MAPPING_DEFAULT => {
  521. LOCATION_COMPONENT_PATTERN
  522. => qr{\A // ([^/]+) /+ ([^/]+)_svn /+(.*) \z}xms,
  523. BROWSER_URL_TEMPLATE
  524. => 'http://{1}/projects/{2}/intertrac/source:{3}{4}',
  525. BROWSER_REV_TEMPLATE => '@{1}',
  526. },
  527. # Default web browser
  528. WEB_BROWSER => 'firefox',
  529. },
  530. };
  531. # Backward compatibility: the REPOS setting is equivalent to the URL setting
  532. $self->{setting}{REPOS} = $self->{setting}{URL};
  533. # Alias the REVISION and TRAC setting to URL_REVISION and URL_TRAC
  534. $self->{setting}{REVISION} = $self->{setting}{URL_REVISION};
  535. bless $self, $class;
  536. return $self;
  537. }
  538. # ------------------------------------------------------------------------------
  539. # SYNOPSIS
  540. # $value = $obj->X;
  541. # $obj->X ($value);
  542. #
  543. # DESCRIPTION
  544. # Details of these properties are explained in the "new" method.
  545. # ------------------------------------------------------------------------------
  546. for my $name (qw/central_config user_config user_id verbose/) {
  547. no strict 'refs';
  548. *$name = sub {
  549. my $self = shift;
  550. # Argument specified, set property to specified argument
  551. if (@_) {
  552. $self->{$name} = $_[0];
  553. }
  554. # Default value for property
  555. if (not defined $self->{$name}) {
  556. if ($name eq 'central_config') {
  557. # Central configuration file
  558. if (-r catfile (dirname ($FindBin::Bin), 'etc', 'fcm.cfg')) {
  559. $self->{$name} = catfile (
  560. dirname ($FindBin::Bin), 'etc', 'fcm.cfg'
  561. );
  562. } elsif (-r catfile ($FindBin::Bin, 'fcm.cfg')) {
  563. $self->{$name} = catfile ($FindBin::Bin, 'fcm.cfg');
  564. }
  565. } elsif ($name eq 'user_config') {
  566. # User configuration file
  567. my $home = (getpwuid ($<))[7];
  568. $home = $ENV{HOME} if not defined $home;
  569. $self->{$name} = catfile ($home, '.fcm')
  570. if defined ($home) and -r catfile ($home, '.fcm');
  571. } elsif ($name eq 'user_id') {
  572. # User ID of current process
  573. my $user = (getpwuid ($<))[0];
  574. $user = $ENV{LOGNAME} if not defined $user;
  575. $user = $ENV{USER} if not defined $user;
  576. $self->{$name} = $user;
  577. } elsif ($name eq 'verbose') {
  578. # Verbose mode
  579. $self->{$name} = exists $ENV{FCM_VERBOSE} ? $ENV{FCM_VERBOSE} : 1;
  580. }
  581. }
  582. return $self->{$name};
  583. }
  584. }
  585. # ------------------------------------------------------------------------------
  586. # SYNOPSIS
  587. # $flag = $obj->is_initialising();
  588. #
  589. # DESCRIPTION
  590. # Returns true if this object is initialising.
  591. # ------------------------------------------------------------------------------
  592. sub is_initialising {
  593. my ($self, $value) = @_;
  594. if (defined($value)) {
  595. $self->{initialising} = $value;
  596. }
  597. return $self->{initialising};
  598. }
  599. # ------------------------------------------------------------------------------
  600. # SYNOPSIS
  601. # %hash = %{ $obj->X () };
  602. # $obj->X (\%hash);
  603. #
  604. # $value = $obj->X ($index);
  605. # $obj->X ($index, $value);
  606. #
  607. # DESCRIPTION
  608. # Details of these properties are explained in the "new" method.
  609. #
  610. # If no argument is set, this method returns a hash containing a list of
  611. # objects. If an argument is set and it is a reference to a hash, the objects
  612. # are replaced by the the specified hash.
  613. #
  614. # If a scalar argument is specified, this method returns a reference to an
  615. # object, if the indexed object exists or undef if the indexed object does
  616. # not exist. If a second argument is set, the $index element of the hash will
  617. # be set to the value of the argument.
  618. # ------------------------------------------------------------------------------
  619. for my $name (qw/variable/) {
  620. no strict 'refs';
  621. *$name = sub {
  622. my ($self, $arg1, $arg2) = @_;
  623. # Ensure property is defined as a reference to a hash
  624. $self->{$name} = {} if not defined ($self->{$name});
  625. # Argument 1 can be a reference to a hash or a scalar index
  626. my ($index, %hash);
  627. if (defined $arg1) {
  628. if (ref ($arg1) eq 'HASH') {
  629. %hash = %$arg1;
  630. } else {
  631. $index = $arg1;
  632. }
  633. }
  634. if (defined $index) {
  635. # A scalar index is defined, set and/or return the value of an element
  636. $self->{$name}{$index} = $arg2 if defined $arg2;
  637. return (
  638. exists $self->{$name}{$index} ? $self->{$name}{$index} : undef
  639. );
  640. } else {
  641. # A scalar index is not defined, set and/or return the hash
  642. $self->{$name} = \%hash if defined $arg1;
  643. return $self->{$name};
  644. }
  645. }
  646. }
  647. # ------------------------------------------------------------------------------
  648. # SYNOPSIS
  649. # $setting = $obj->setting (@labels);
  650. # $obj->setting (\@labels, $setting);
  651. #
  652. # DESCRIPTION
  653. # This method returns/sets an item under the setting hash table. The depth
  654. # within the hash table is given by the list of arguments @labels, which
  655. # should match with the keys in the multi-dimension setting hash table.
  656. # ------------------------------------------------------------------------------
  657. sub setting {
  658. my $self = shift;
  659. if (@_) {
  660. my $arg1 = shift;
  661. my $s = $self->{setting};
  662. if (ref ($arg1) eq 'ARRAY') {
  663. # Assign setting
  664. # ------------------------------------------------------------------------
  665. my $value = shift;
  666. while (defined (my $label = shift @$arg1)) {
  667. if (exists $s->{$label}) {
  668. if (ref $s->{$label} eq 'HASH') {
  669. $s = $s->{$label};
  670. } else {
  671. $s->{$label} = $value;
  672. last;
  673. }
  674. } else {
  675. if (@$arg1) {
  676. $s->{$label} = {};
  677. $s = $s->{$label};
  678. } else {
  679. $s->{$label} = $value;
  680. }
  681. }
  682. }
  683. } else {
  684. # Get setting
  685. # ------------------------------------------------------------------------
  686. return _get_hash_value ($s->{$arg1}, @_) if exists $s->{$arg1};
  687. }
  688. }
  689. return undef;
  690. }
  691. # ------------------------------------------------------------------------------
  692. # SYNOPSIS
  693. # $obj->get_config ();
  694. #
  695. # DESCRIPTION
  696. # This method reads the configuration settings from the central and the user
  697. # configuration files.
  698. # ------------------------------------------------------------------------------
  699. sub get_config {
  700. my $self = shift;
  701. $self->_read_config_file ($self->central_config);
  702. $self->_read_config_file ($self->user_config);
  703. return;
  704. }
  705. # ------------------------------------------------------------------------------
  706. # SYNOPSIS
  707. # $obj->_read_config_file ();
  708. #
  709. # DESCRIPTION
  710. # This internal method reads a configuration file and assign values to the
  711. # attributes of the current instance.
  712. # ------------------------------------------------------------------------------
  713. sub _read_config_file {
  714. my $self = shift;
  715. my $config_file = $_[0];
  716. if (!$config_file || !-f $config_file || !-r $config_file) {
  717. return;
  718. }
  719. my $cfgfile = Fcm::CfgFile->new (SRC => $config_file, TYPE => 'FCM');
  720. $cfgfile->read_cfg ();
  721. LINE: for my $line (@{ $cfgfile->lines }) {
  722. next unless $line->label;
  723. # "Environment variables" start with $
  724. if ($line->label =~ /^\$([A-Za-z_]\w*)$/) {
  725. $ENV{$1} = $line->value;
  726. next LINE;
  727. }
  728. # "Settings variables" start with "set"
  729. if ($line->label_starts_with_cfg ('SETTING')) {
  730. my @tags = $line->label_fields;
  731. shift @tags;
  732. @tags = map {uc} @tags;
  733. $self->setting (\@tags, $line->value);
  734. next LINE;
  735. }
  736. # Not a standard setting variable, put in internal variable list
  737. (my $label = $line->label) =~ s/^\%//;
  738. $self->variable ($label, $line->value);
  739. }
  740. 1;
  741. }
  742. # ------------------------------------------------------------------------------
  743. # SYNOPSIS
  744. # $ref = _get_hash_value (arg1, arg2, ...);
  745. #
  746. # DESCRIPTION
  747. # This internal method recursively gets a value from a multi-dimensional
  748. # hash.
  749. # ------------------------------------------------------------------------------
  750. sub _get_hash_value {
  751. my $value = shift;
  752. while (defined (my $arg = shift)) {
  753. if (exists $value->{$arg}) {
  754. $value = $value->{$arg};
  755. } else {
  756. return undef;
  757. }
  758. }
  759. return $value;
  760. }
  761. # ------------------------------------------------------------------------------
  762. 1;
  763. __END__