root/trunk/m2/m2

Revision 424, 15.1 kB (checked in by krobillard, 18 months ago)

m2 - Added qt-static. Implemented this for Mac OS.

  • Property svn:executable set to *
Line 
1#!/usr/bin/rebol -qs
2
3REBOL [
4        RCS: {$Id: m2,v 1.16 2005/06/21 05:07:06 karl Exp $}
5    Title: "m2"
6    Version: 0.4.0
7    Rights: "Copyright (C) 2001-2006 Karl Robillard"
8    Author: "Karl Robillard"
9        Date: 27-May-2001
10        Home: http://wsrebol.sf.net/
11    Purpose: {Generates project makefiles.}
12        History: [
13                0.0.1 [27-May-2001 "Version 2 of rmake."]
14        ]
15        TODO: {
16                * Remove files outside the build directory from dist rule.
17                * Add Qt moc files to sources but not to distribution rule.
18        }
19
20        Template-notes: {
21        These words are defined in the template file:
22                generate_makefile
23
24                exe_target
25                lib_target
26                shlib_target
27                rule_target
28
29                makerule_cxx
30                makerule_asm
31                makerule_c
32        }
33
34        ; NOTE: Symbolic links don't work!
35]
36
37
38verbose: false
39
40debug_include: false
41idprint: func [ blk ] [ if debug_include [ print blk ] ]
42
43; Saving system/script/path before any change-dir.
44start_dir: copy system/script/path
45
46
47m2: context [
48
49        ;--------------------------------------
50        ; These are constant for each makefile.
51
52        makefile: %Makefile
53        project_name: "project"
54        project_ver: none
55        default_block: none
56
57        project_version: func [{Returns string with name and version}] [
58                either none? project_ver [
59                        project_name
60                ][
61                        rejoin [ project_name "-" project_ver ]
62                ]
63        ]
64
65        ct: none
66        targets: []
67    output_buf: make string! 1024
68
69        ; This contains file! block! pairs.  The block contains the files
70        ; included in the file.
71        include_dict: []
72
73        distribution_files: []
74
75
76        ;--------------------------------------
77        ; These can be changed for each target.
78
79        configuration: context [
80                release: debug: warn: false
81                opengl: qt: qt-static: x11: false
82        ]
83
84        target_env: context [
85                name: none
86                uc_name: none
87                output_file: none
88                link_cxx: false
89
90                objdir: ""
91                output_dir: ""
92                obj_ext: ".o"
93                cxx_ext: ".cpp"
94                defines: []
95
96                include_paths: []
97                link_paths: []
98                link_libs: []
99
100                header_files: []
101                source_files: []
102                object_files: []
103
104                moc_files: []
105                srcmoc_files: []
106
107                menv_cflags: {}
108                menv_cxxflags: {}
109                menv_lflags: {}
110
111                cfg: none ;make configuration []
112       
113                configure: none
114                macro_text: none
115                rule_text: none
116
117                rule_makeobj: func [cc flags obj src] [
118                        ; Default to GNU
119                        rejoin [ "^(tab)$(" cc ") -c $(" uc_name flags ") -o " obj
120                                         " $(" uc_name "_INCPATH) " src ]
121                ]
122                makerule_cxx: func [obj src] [ link_cxx: true
123                                                                           rule_makeobj "CXX" "_CXXFLAGS" obj src ]
124                makerule_asm: func [obj src] [ rule_makeobj "AS" "_ASFLAGS" obj src ]
125                makerule_c:   func [obj src] [ rule_makeobj "CC" "_CFLAGS" obj src ]
126
127                file_rules: [
128                        ".cpp" makerule_cxx
129                        ".cxx" makerule_cxx
130                        ".cc"  makerule_cxx
131                        ".s"   makerule_asm
132                        ".c"   makerule_c
133                ]
134
135                make_obj_rule: func [
136                        {Builds rules which make object files.
137                         Dependencies are automatically generated by recursively searching
138             in sources and included files.
139                         Called from the template.}
140                        /local str src srcfile dependencies inc common rule
141                ][
142                        str: make string! 512
143                        src: source_files
144                        foreach obj object_files [
145                                append str rejoin [ obj ": " src/1 ]
146
147                                srcfile: to-file src/1
148
149                                either exists? srcfile [
150                                        dependencies: select m2/include_dict srcfile
151                                ][
152                                        print [ "make_obj_rule: Warning -" srcfile "not found" ]
153                                        dependencies: []
154                                ]
155
156                                either none? dependencies [
157                                        append str "^/"
158                                ][
159                                        either empty? dependencies [
160                                                append str "^/"
161                                        ][
162                                                append str " \^/"
163                                                foreach dep dependencies [
164                                                        inc: select m2/include_dict dep
165                                                        if none? inc [
166                                                          m2/append_include_dict dependencies include_paths
167                                                          inc: select m2/include_dict dep
168                                                        ]
169                                                        common: intersect dependencies inc
170                                                        append dependencies difference inc common
171                                                ]
172
173                                                append str expand_list_gnu sort dependencies
174                                        ]
175                                ]
176
177                                ; Explicitly state rule
178                                foreach [ext r] file_rules [
179                                        ;print [ext get r]
180                                        if find src/1 ext [
181                                                append str rejoin [ do r obj src/1 "^/^/" ]
182                                                break
183                                        ]
184                                ]
185
186                                src: next src
187
188                                append header_files dependencies
189                        ]
190
191                        header_files: sort intersect header_files header_files
192
193                        str
194                ]
195
196                moc_rule: func [ /local str src ] [
197                        str: make string! 0
198                        src: srcmoc_files
199                        foreach file moc_files [
200                                append str rejoin [ src/1 ": " file ]
201                                append str rejoin [ "^/^(tab)$(MOC) " file " -o " src/1 "^/^/" ]
202
203                                src: next src
204                        ]
205                        str
206                ]
207        ]
208
209        ;--------------------------------------
210
211        static_lib_targets: []
212
213        local_libs: func [
214                ; Returns string of libraries from libs which are built by this
215                ; project file.
216                libs
217                /local l str
218        ][
219                str: make string! 0
220                foreach [base path] static_lib_targets [
221                        if l: find libs base [
222                                append str rejoin [#" " path]
223                                ;probe first l
224                        ]
225                ]
226                str
227        ]
228
229
230        header_files_used: func [
231                ; Returns a block containing all header files used in the project.
232                /local blk
233        ][
234                blk: copy []
235                foreach [ f b ] include_dict [
236                        append blk b
237                ]
238                sort intersect blk blk
239        ]
240
241
242        append_include_dict: func [
243                "Returns a block all files included from files"
244                files paths /local headers blk ]
245        [
246                headers: copy []
247
248                ; Should make include_dict a hash?
249                forall files [
250                        if none? (select include_dict files/1) [
251                                blk: included_files files/1 paths
252                                append headers blk
253
254                                append include_dict files/1
255                                append/only include_dict blk
256                        ]
257                ]
258
259                sort intersect headers headers
260        ]
261
262        add_target: function [target blk] [] [
263                ct: target
264                append targets ct
265
266                do default_block
267                do blk
268
269                if (length? ct/objdir) > 0 [
270                        if not exists? ct/objdir [
271                                make-dir ct/objdir
272                        ]
273                ]
274
275                ct/configure
276                ct/object_files: make_file_list ct/source_files ct/objdir ct/obj_ext
277
278                ct/header_files: append_include_dict ct/source_files ct/include_paths
279                ;probe include_dict
280                ;probe ct/header_files
281
282                if ct/cfg/qt [
283                        add_moc_files ct ct/header_files
284
285                        ; Uncomment this to search cpp files for Q_OBJECT.
286                        ;add_moc_files source_files
287
288                        append ct/object_files
289                                make_file_list ct/srcmoc_files ct/objdir ct/obj_ext
290
291                        append ct/source_files ct/srcmoc_files
292                ]
293        ]
294
295        build_makefile: func [ projfile template ] [
296                do template
297                do projfile
298                clear output_buf
299                write makefile generate_makefile
300        ]
301]
302
303
304;------------------------------------------------------------------
305; Used in template file.
306
307
308emit: func [data] [append m2/output_buf reduce data]
309
310
311;------------------------------------------------------------------
312; Used in project file.
313
314
315project:  func [str] [ m2/project_name: str ]
316version:  func [str] [ m2/project_ver: str ]
317default:  func [blk] [ m2/default_block: blk ]
318objdir:   func [dir] [ m2/ct/objdir: dir ]
319into:     func [dir] [ m2/ct/output_dir: verify_slash dir ]
320
321cflags:   func [str [string!]] [ add_flags m2/ct/menv_cflags str ]
322cxxflags: func [str [string!]] [ add_flags m2/ct/menv_cxxflags str ]
323lflags:   func [str [string!]] [ add_flags m2/ct/menv_lflags str ]
324
325linux:
326macx:
327sun:
328unix:
329win32:    func [blk [block!]] []        ; skip block by default
330
331opengl:   func [{Using OpenGL libraries.}]     [ m2/ct/cfg/opengl: true ]
332qt3:      func [{Using Troll Tech's Qt 3.}]    [ m2/ct/cfg/qt: 3 ]
333qt:       func [{Using Troll Tech's Qt 4.} libs [block!]] [ m2/ct/cfg/qt: libs ]
334qt-static: does [m2/ct/cfg/qt-static: true]
335x11:      func [{Using X11 libraries.}]        [ m2/ct/cfg/x11: true ]
336
337debug:    func [{Building debug version.}]     [ m2/ct/cfg/debug: true ]
338release:  func [{Optimize for release build.}] [ m2/ct/cfg/release: true ]
339warn:     func [{Enable compiler warnings.}]   [ m2/ct/cfg/warn: true ]
340
341define:   func [str [string!]] [ append m2/ct/defines parse str none ]
342
343include_from: func [list [string! block! file!]] [
344        if string? list [
345                list: parse list none
346        ]
347        ; TODO: Run conv_slash on each item.
348        append m2/ct/include_paths reduce list
349]
350
351libs: func [list [string! block! file!]] [
352        either string? list [
353                append m2/ct/link_libs parse list none
354        ][
355                append m2/ct/link_libs list
356        ]
357]
358
359libs_from: func [dir list] [
360        append m2/ct/link_paths dir
361        libs list
362]
363
364dist: func [arg [block!]] [
365        append m2/distribution_files arg
366]
367
368sources: func [arg [block!]] [
369        append m2/ct/source_files arg
370]
371
372sources_from: func [path files [block!]] [
373        ;include_from path
374        verify_slash path
375        forall files [
376                append m2/ct/source_files join path files/1
377        ]
378]
379
380
381exe: func [{Builds executable rule.} basename blk ]
382[
383        m2/add_target (make exe_target [
384                        name: basename
385                        uc_name: uppercase copy basename
386                        cfg: make m2/configuration []
387                ]) blk
388]
389
390
391lib: func [{Builds static library rule.} basename blk ]
392[
393        m2/add_target (make lib_target [
394                        name: basename
395                        uc_name: uppercase copy basename
396                        cfg: make m2/configuration []
397                ]) blk
398
399        append m2/static_lib_targets reduce [basename m2/ct/output_file]
400]
401
402shlib: func [{Builds shared library rule.} basename blk ]
403[
404        m2/add_target (make shlib_target [
405                        name: basename
406                        uc_name: uppercase copy basename
407                        cfg: make m2/configuration []
408                ]) blk
409]
410
411
412rule:  func [{Builds generic make rule.} basename blk ]
413[
414        m2/add_target (make rule_target [
415                        name: basename
416                        uc_name: uppercase copy basename
417                        cfg: make m2/configuration []
418                ]) blk
419]
420
421
422gnu_string: func [
423        {Returns string of items each with a prefix.}
424        prefix [string!]
425        items [block!]
426        /local str
427][
428        str: make string! 64
429    forall items [
430        append str either (find items/1 " ") [
431                rejoin [ { } prefix {"} items/1 {"} ]
432        ][
433                rejoin [ { } prefix items/1 ]
434        ]
435    ]
436        remove str
437]
438
439
440comment {
441makesub_gnu: func [
442        {Make subdirectory rule suitable for GNU make.}
443        rulename dirs /local dir ]
444[
445        append make_subdirs rejoin [ ".PHONY: " rulename "^/" rulename ":^/" ]
446        foreach dir dirs [
447                append make_subdirs rejoin [ "^(tab)make -C " dir "^/" ]
448        ]
449
450        append make_subdirs rejoin [ "^/" ".PHONY: " rulename "clean^/"
451                                 rulename "clean:^/" ]
452        foreach dir dirs [
453                append make_subdirs rejoin [ "^(tab)make -C " dir " clean^/" ]
454        ]
455]
456}
457
458
459;------------------------------------------------------------------
460; Private
461
462
463;unix-platforms: [ 4 6 7 8 9 10 11 12 19 22 23 ]
464;unix:    if find unix-platforms system/version/4
465;windows: if system/version/4 = 3
466
467
468add_flags: func [ flags str ] [
469    either empty? flags [
470        append flags trim/lines str
471    ][
472        append flags join " " (trim/lines str)
473    ]
474]
475
476
477strip_ext: func [ file /local lastdot ] [
478    lastdot: find/last file "."
479    if lastdot [
480        remove/part lastdot (tail file)
481    ]
482    return file
483]
484
485
486verify_slash: func [path [file! url!] /local lp] [
487    lp: last path
488    if all [
489        lp <> #"/"
490        lp <> #"\"
491    ][
492        append path #"/"
493    ]
494    path
495]
496
497
498make_file_list: func [
499        "Copy a block of files with changed path and extension"
500        src [block!]
501        dir
502        extension
503][
504        obj: copy/deep src
505        either empty? dir [
506                forall obj [
507                        strip_ext obj/1
508                        append obj/1 extension
509                ]
510        ][
511                forall obj [
512                        file: second split-path obj/1
513                        obj/1: rejoin [ verify_slash dir strip_ext file extension ]
514                ]
515        ]
516        return head obj
517]
518
519
520find_include_file: func [
521        {Checks if a file exists in the current directory or any set of paths.}
522        file [file!]
523        paths [block!]
524        /local path full
525][
526        idprint [ " " file ]
527
528    if exists? file [ return file ]
529
530    forall paths [
531        path: to-file paths/1
532        verify_slash path
533        full: join path file
534
535                idprint [ "   " full ]
536
537        if exists? full [ return full ]
538    ]
539    none
540]
541
542
543included_files: func [
544    {Returns a block of the files which are included in a C/C++ file.
545         Addes   #include "file.h"
546         Ignores #include <file.h>
547         Ignores #include MACRO}
548    file [file!]   "File to check for #include statements"
549    paths [block!] "Paths to check for included files"
550    /local blk header ifile
551][
552    blk: copy []
553
554        if not exists? file [
555                print [ "included_files: " file "not found" ]
556                return blk
557        ]
558
559    foreach line read/lines file [
560
561        ; BUG: #include can be commented or defined out but will still be
562        ; included here.  This causes errors when windows-only code includes
563                ; files with paths (using backslash) and we are compiling on a
564                ; non-windows system.
565
566        if find/case line "#include" [
567            if find/any line {"*"} [
568                parse line [thru {"} copy header to {"}]
569                append blk to-file header
570            ]
571        ]
572    ]
573
574    blk: intersect blk blk   ; Removes duplicates.
575
576        if debug_include [ print ["Finding include files for" file] probe blk ]
577
578        forall blk [
579                ifile: find_include_file blk/1 paths
580                either none? ifile [
581                        print rejoin ["included_files: " blk/1 " (from " file
582                          ") not found!"]
583                        remove blk
584                        blk: back blk
585                ][
586                        blk/1: ifile
587                ]
588        ]
589        blk: head blk
590]
591
592
593do_tags: func [
594    {Replace each tag in a string with the value of the tag.
595     Individual '<' and '>' are allowed, but they cannot be used
596     between other < > pairs. }
597    str [string!]
598    /local begin exp
599][
600    begin: none
601    forall str [
602        if str/1 = #"<" [
603            begin: str
604        ]
605        if str/1 = #">" [
606            if not none? begin [
607                exp: copy/part (next begin) str
608                change/part begin (do exp) (next str)
609
610                ; Must continue from start of tag because it may have been
611                ; replaced with "".  If we don't continue from begin we will
612                ; miss any closely following '<' or '>'.
613                str: begin
614
615                begin: none
616            ]
617        ]
618    ]
619
620    comment {
621    ; This parse rule causes nearby tags to be missed.
622    parse str [
623        any [
624            to "<" begin: thru ">" ending:
625            (exp: copy/part (next begin) (back ending)
626             change/part begin (do exp) ending)
627        ]
628    ]
629    }
630
631    head str
632]
633
634
635; Nothing by default.
636conv_slash: func [ file ] [ file ]
637
638
639expand_list_gnu: func [
640    {Returns a string with each file on a seperate line.}
641    files [block!]
642        /part "Do not erase trailing space and slash"
643    /local x
644][
645    str: make string! 64
646    foreach file files [
647        append str rejoin [ {^(tab)} conv_slash file { \^/} ]
648    ]
649
650        if not part [
651                x: find/last str " "
652                if x [
653                        remove/part x 2
654                ]
655        ]
656    return str
657]
658
659
660add_moc_files: function [ ct files [block!] ][ blk found ]
661[
662    blk: make block! 0
663
664    foreach file files [
665        if find/case read file "Q_OBJECT" [
666            append ct/moc_files file
667
668            set [ path file ] split-path file
669
670                        ; MOC bug - specifying "./" on output file creates bad include
671                        ; statements.
672                        if path = %"./" [ path: %"" ]
673
674            append ct/srcmoc_files join path
675                                ["moc_" (strip_ext file) ct/cxx_ext]
676        ]
677    ]
678
679    return blk
680]
681
682
683;------------------------------------------------------------------
684
685
686project_file: %project.r
687
688; Assuming template resides with m2 by defualt.
689template_file: join start_dir %m2_template.r
690
691
692change-dir system/script/parent/path
693if string? system/script/args [
694    args: parse system/script/args none
695    forall args [
696                switch/default args/1 [
697                        "-t" [
698                                args: next args
699                                template_file: to-file args/1
700                        ]
701                        "-o" [
702                                args: next args
703                                m2/makefile: to-file args/1
704                        ]
705                ][
706                        project_file: to-file args/1
707                ]
708        ]
709]
710
711;print [ project_file template_file m2/makefile ]
712
713if not exists? template_file [
714        print [ "Template" template_file "not found." ]
715        quit
716]
717
718either exists? project_file [
719        m2/build_makefile project_file template_file
720][
721        print [ project_file "does not exist; Please specify project file." ]
722]
723
724;probe m2/header_files_used
725
726quit
727
728
729;EOF
Note: See TracBrowser for help on using the browser.