×

Welcome to TagMyCode

Please login or create account to add a snippet.
0
0
 
0
Language: Perl
Posted by: jeremias trindade
Added: Dec 5, 2015 12:18 AM
Modified: Feb 14, 2016 9:35 PM
Views: 28
Tags: no tags
Este script lê todos os arquivos fontes do diretório e subdiretórios, cria uma lista de dependências e depois gera um arquivo Makefile. Útil para quem não gosta de escrever esse tipo de arquivo. :-)

Ele ainda está muito ineficiente, mas pelo menos funciona na forma em que se encontra.

OBS: É necessário instalar o Template Toolkit (http://template-toolkit.org/)
  1. use strict;
  2. use warnings;
  3. use Template;
  4. use File::Find;
  5. use Data::Dumper;
  6.  
  7.  
  8.  
  9.  
  10.  
  11. ###############################################################################
  12. # CONFIGURATION
  13. ###############################################################################
  14. my $SOURCE = "./src";
  15. my $TESTS  = "./tests";
  16.  
  17. my $CONFIG = "";
  18.  
  19. if ((lc $ARGV[0]) =~ m/debug/)
  20. {
  21.     $CONFIG = "debug";
  22. }
  23. elsif ((lc $ARGV[0]) =~ m/tests/)
  24. {
  25.     $CONFIG = "tests";
  26. }
  27.  
  28.  
  29.  
  30.  
  31.  
  32. ###############################################################################
  33. # Global vars
  34. ###############################################################################
  35. my @PATHS;
  36. my @CATALOG;
  37. my @OBJECTS;
  38. my @TESTPATHS;
  39. my @TESTOBJECTS;
  40.  
  41. my $indent = 0;
  42.  
  43.  
  44.  
  45.  
  46. ###############################################################################
  47. # Main
  48. ###############################################################################
  49. {
  50.     my $tmp;
  51.     my $objfile;
  52.     my $srcfile;
  53.  
  54.     puts("Starting scanning...");
  55.    
  56.     $indent++;
  57.     find(\&find_files, $SOURCE);
  58.         find(\&find_files, $TESTS) if $CONFIG eq "tests";
  59.     $indent--;
  60.    
  61.     change_path_from_win_2_unix();
  62.    
  63.     foreach my $file(@CATALOG)
  64.     {
  65.         next if $file->{name} =~ m/\.o$/;
  66.        
  67.         puts("Looking for " . $file->{name} . "'s dependencies.");
  68.         $indent++;
  69.         create_dependency_list(\$file);
  70.         $indent--;
  71.     }
  72.  
  73.     foreach my $file(@CATALOG)
  74.     {
  75.         my @SRCLIST;
  76.         my @OBJLIST;
  77.         my @DEPENDENCYLIST;
  78.        
  79.         $srcfile = $file->{name};
  80.         next if $srcfile !~ m/\.cpp$/;
  81.  
  82.         $objfile = $srcfile;
  83.        
  84.         $objfile =~ s/^.+\///;
  85.         $objfile =~ s/\.cpp$/.o/;
  86.        
  87.         $indent++;
  88.         push @SRCLIST, $srcfile;
  89.        
  90.         my @deps = @{ getDependencies(\$file) };
  91.        
  92.         foreach my $itDep(@deps)
  93.         {
  94.             $tmp = $$itDep->{name};
  95.             next if not defined $tmp;
  96.            
  97.             if ($tmp =~ m/\.h$/)
  98.             {
  99.                 $tmp =~ s/\.h$/.cpp/;
  100.                 if (not $tmp eq $srcfile and -e $tmp)
  101.                 {
  102.                     $tmp =~ s/\.cpp$/.o/;
  103.                     $tmp =~ s/^.+\///;
  104.                 }
  105.                 else
  106.                 {
  107.                     $tmp =~ s/\.cpp$/.h/;
  108.                 }
  109.             }
  110.  
  111.             push @SRCLIST, $tmp if $tmp =~ m/\.h$/;
  112.             push @OBJLIST, $tmp if $tmp =~ m/\.o$/;
  113.  
  114.                         my $found = 0;
  115.                         if($file->{name} =~ m/^\.\/tests/)
  116.                         {
  117.                                 foreach my $it(@TESTOBJECTS)
  118.                                 {
  119.                                         if($it->{name} eq $objfile)
  120.                                         {
  121.                                                 $found = 1;
  122.                                                 last;
  123.                                         }
  124.                                 }
  125.                                 push @TESTOBJECTS, { name => $objfile, dep_obj => \@OBJLIST, dep_src => \@SRCLIST } if not $found;
  126.                         }
  127.                         else
  128.                         {
  129.                                 foreach my $it(@OBJECTS)
  130.                                 {
  131.                                         if($it->{name} eq $objfile)
  132.                                         {
  133.                                                 $found = 1;
  134.                                                 last;
  135.                                         }
  136.                                 }
  137.                                 push @OBJECTS, { name => $objfile, dep_obj => \@OBJLIST, dep_src => \@SRCLIST } if not $found;
  138.                         }
  139.  
  140.         }
  141.         $indent--;
  142.     }
  143.    
  144.     if (scalar @CATALOG > 0)
  145.     {
  146.                 makemake();
  147.         }
  148.    
  149.     print "\n\nUpdating Makefile...\n\n";
  150. }
  151.  
  152.  
  153.  
  154.  
  155. sub change_path_from_win_2_unix
  156. {
  157.     my $str = "";
  158.    
  159.     foreach my $file(@CATALOG)
  160.     {
  161.         next if $file->{name} =~ m/\.o$/;
  162.        
  163.         my $changed = 0;
  164.         open(my $HFILE, "<", $file->{name}) or die "Cant open file " . $file->{name} . ": $!\n";
  165.         my @lines = <$HFILE>;
  166.         close $HFILE;
  167.  
  168.         foreach my $it(@lines)
  169.         {
  170.             next if $it !~ m/^(\s|\t)*#(\s|\t)*include/;
  171.            
  172.             if ($it =~ m/\\/)
  173.             {
  174.                 $it =~ s/\\/\//g;
  175.                 $changed = 1;
  176.             }
  177.         }
  178.        
  179.         if ($changed)
  180.         {
  181.             puts("Updating file: " . $file->{name});
  182.             open(my $HFILE, ">", $file->{name}) or die "Cant open file " . $file->{name} . ": $!\n";
  183.             foreach my $it(@lines)
  184.             {
  185.                 print $HFILE $it;
  186.             }
  187.             close $HFILE;
  188.         }
  189.     }
  190. }
  191.  
  192.  
  193.  
  194.  
  195. sub getDependencies
  196. {
  197.     my @aux;
  198.     my $self = shift;
  199.  
  200.     if (defined $$self->{dependencies})
  201.     {
  202.         my @dependencies = @{ $$self->{dependencies} };
  203.    
  204.         push @aux, @dependencies;    
  205.        
  206.         foreach my $itDep(@dependencies)
  207.         {
  208.             my @tmp = @{ getDependencies($itDep) };
  209.             foreach my $itTmp(@tmp)
  210.             {
  211.                 push @aux, $itTmp if not registered(\@aux, $itTmp);            
  212.             }
  213.         }
  214.         }
  215.     else
  216.     {
  217.         puts($$self->{name} . " has no dependencies.");
  218.         print Dumper($$self);
  219.     }
  220.        
  221.     return \@aux;
  222. }
  223.  
  224.  
  225.  
  226.  
  227. sub registered
  228. {
  229.     my $reg = 0;
  230.     my ($refList, $refFile) = @_;
  231.    
  232.     foreach my $it(@$refList)
  233.     {
  234.         if (defined $$refFile->{id} and defined $$it->{id})
  235.         {
  236.             if ($$refFile->{id} == $$it->{id})
  237.             {
  238.                 $reg = 1;
  239.                 last;
  240.             }
  241.         }
  242.        
  243.     }
  244.    
  245.     return $reg;
  246. }
  247.  
  248.  
  249.  
  250.  
  251. ###############################################################################
  252. #
  253. ###############################################################################
  254. sub find_files
  255. {
  256.     my @cppdep;
  257.     my @objdep;
  258.  
  259.     my $cppfile;
  260.     my $objfile;
  261.     my $fname = $File::Find::name;
  262.    
  263.     if (-d)
  264.     {
  265.                 if($fname =~ m/^$TESTS/)
  266.                 {
  267.                         $fname =~ s/^$TESTS//;
  268.  
  269.                         foreach my $path(@TESTPATHS)
  270.                         {
  271.                                 return if $fname eq $path;
  272.                         }
  273.                        
  274.                         $fname =~ s/^(\/|\\)//;
  275.                         push @TESTPATHS, $fname;
  276.                 }
  277.                 elsif($fname =~ m/^$SOURCE/)
  278.                 {
  279.                         $fname =~ s/^$SOURCE//;
  280.                         foreach my $path(@PATHS)
  281.                         {
  282.                                 return if $fname eq $path;
  283.                         }
  284.                        
  285.                         $fname =~ s/^(\/|\\)//;
  286.                         push @PATHS, $fname;
  287.                 }
  288.                
  289.         puts("Adding path: " . $_);
  290.     }
  291.     elsif (m/\.(h|cpp)$/)
  292.     {
  293.         my $id = scalar @CATALOG;
  294.         $fname = $File::Find::name;
  295.  
  296.         $fname =~ s/^\.\///;
  297.         puts("Acquiring file " . $fname);
  298.         $indent++;
  299.         if ($fname =~ m/\.cpp$/)
  300.         {
  301.             $cppfile = { id => $id, name => $fname, dependencies => \@cppdep };
  302.             push @CATALOG, $cppfile;
  303.            
  304.             $id++;
  305.             $fname =~ s/\.cpp$/.o/;
  306.             puts("Creating object file: " . $fname);
  307.             $objfile = { id => $id, name => $fname, dependencies => \@objdep };
  308.             push @objdep, \$cppfile;
  309.             push @CATALOG, $objfile;
  310.         }
  311.         else
  312.         {
  313.             $cppfile = { id => $id, name => $fname, dependencies => \@cppdep };
  314.             push @CATALOG, $cppfile;
  315.         }
  316.         $indent--;
  317.     }
  318. }
  319.  
  320.  
  321.  
  322.  
  323.  
  324.  
  325. ###############################################################################
  326. #
  327. ###############################################################################
  328. sub create_dependency_list
  329. {
  330.     my @dependencies;
  331.  
  332.     my $dp;
  333.     my $file = shift;
  334.     $file = $$file;
  335.     my $filename = $file->{name};
  336.  
  337.     open(my $HFILE, "<", $filename) or die "Cant open " . $filename . ": $!\n";
  338.    
  339.     puts("Parsing " . $filename);
  340.     while (<$HFILE>)
  341.     {
  342.         next if not m/^(\s|\t)*#(\s|\t)*include(\s|\t)+".+"/;
  343.         s/^[^"]+"|"[^"]*$//g;
  344.        
  345.         puts("Searching the catalog...");
  346.        
  347.         $indent++;
  348.         my $refDependency = get_dependency_from_catalog($_);
  349.         next unless defined $refDependency;
  350.        
  351.         @dependencies = @{ $file->{dependencies} };
  352.         push @dependencies, $refDependency;
  353.         $file->{dependencies} = \@dependencies;
  354.         $indent--;
  355.     }
  356.     close $HFILE;
  357. }
  358.  
  359.  
  360.  
  361.  
  362. ###############################################################################
  363. #
  364. ###############################################################################
  365. sub get_dependency_from_catalog
  366. {
  367.     my $filename = shift;
  368.    
  369.     foreach my $file(@CATALOG)
  370.     {
  371.         my $f1 = lc $filename;
  372.         my $f2 = lc $file->{name};
  373.         next if $f1 !~ m/$f2$/;
  374.        
  375.         puts("Found dependency: " . $file->{name});
  376.         return \$file;
  377.     }
  378.    
  379.     puts("*** Not in the catalog: " . $filename);
  380.     return undef;
  381. }
  382.  
  383.  
  384.  
  385.  
  386. ###############################################################################
  387. #
  388. ###############################################################################
  389. sub puts
  390. {
  391.     my $msg = shift;
  392.     return;
  393.    
  394.     for(my $i = 0; $i < $indent; $i++)
  395.     {
  396.         print "   ";        
  397.     }
  398.    
  399.     print "($indent) $msg\n";
  400. }
  401.  
  402.  
  403.  
  404.  
  405.  
  406.  
  407. ###############################################################################
  408. #
  409. ###############################################################################
  410. sub makemake
  411. {
  412.     my $makefile = "";
  413.     my $template = "";
  414.     my $tt = new Template({EVAL_PERL=>1});
  415.    
  416.     while (<DATA>)
  417.     {
  418.         $template .= $_;
  419.     }
  420.        
  421.     my $content = { cfg => $CONFIG, paths => \@PATHS, files => \@OBJECTS, testpaths => \@TESTPATHS, testfiles => \@TESTOBJECTS };
  422.    
  423.     $tt->process(\$template, $content, \$makefile) or die $tt->error();
  424.    
  425.     open(my $HFILE, ">", "Makefile") or die "Cant open file 'Makefile': $!\n";
  426.     print $HFILE $makefile;
  427.     close $HFILE;
  428.     #print $makefile;
  429. }
  430.  
  431.  
  432. __DATA__
  433. #
  434. # MAKEFILE GERADO AUTOMATICAMENTE.asdf
  435. #
  436.  
  437.  
  438.  
  439.  
  440. #---------------------------------------------------------------
  441. # CONFIGURAÇÕES DE MONTAGEM    
  442. #---------------------------------------------------------------
  443.  
  444. # Nome do arquivo executavel para qualquer configuracao: debug, release, testes
  445. EXE = ph.exe
  446.  
  447. # Configuracao utilizada para construir o programa.
  448. # Por convencao, o programa final e os arquivos objeto sao  copiados para o diretório build/$(CONFIG)/
  449. CONFIG = [% cfg %]
  450.  
  451. # Define a menor versao do windows que deve ser suportada pelo programa.
  452. WINVERSION = 0x501
  453.  
  454. # Auto explicativo.
  455. BITNESS = 32
  456.  
  457. # Define o modo como as bibliotecas serao inseridas no programa.
  458. # Valores validos: static, dynamic
  459. LINKMODE = static
  460.  
  461. #
  462. #
  463. VERBOSE = yes
  464.  
  465.  
  466. #---------------------------------------------------------------
  467. # FIM
  468. #---------------------------------------------------------------
  469.  
  470.  
  471.  
  472.  
  473. # Funcoes
  474. #----------------------------------------------------------------#
  475. rfind=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rfind,$d/,$2))
  476.  
  477.  
  478.  
  479.  
  480. # Definicao das ferramentas de compilacao, montagem e assistencia
  481. #----------------------------------------------------------------#
  482. CXX         = g++
  483. CP          = sfk -yes copy
  484. RM          = sfk -yes deltree
  485. MKDIR       = sfk -yes mkdir
  486. SHELL       = $(ComSpec)
  487.  
  488.  
  489.  
  490.  
  491. # Flags
  492. #----------------------------------------------------------------#
  493. TESTSFLAGS              = -DTESTS
  494. DEBUGFLAGS              = -g -O0 -DDEBUG
  495. CPPFLAGS                = -DWINVER=$(WINVERSION) -DUNICODE -DSFML_STATIC -DPOCO_STATIC
  496. CXXFLAGS                = -Wall -fmessage-length=0 -std=c++11 -static -static-libgcc -mms-bitfields -m$(BITNESS)
  497.  
  498.  
  499.  
  500.  
  501. # Diretorios
  502. #----------------------------------------------------------------#
  503. ROOT                    ?= .
  504. PROJECT_INC             = $(ROOT)/include
  505. PROJECT_SRC             = $(ROOT)/src
  506. PROJECT_LIB             = $(ROOT)/lib
  507. PROJECT_BIN             = $(ROOT)/bin
  508. PROJECT_TESTS   = $(ROOT)/tests
  509.  
  510. SDK_ROOT                ?= c:/sdk
  511. SDK_INC                 = $(SDK_ROOT)/include
  512. SDK_LIB                 = $(SDK_ROOT)/lib
  513. SDK_BIN                 = $(SDK_ROOT)/bin
  514.  
  515. BUILD_DIR               = $(ROOT)/build
  516. CONFIG_DIR              = $(BUILD_DIR)/$(CONFIG)
  517. OBJS_DIR                = $(CONFIG_DIR)/obj
  518.  
  519.  
  520.  
  521.  
  522. # Bibliotecas
  523. #----------------------------------------------------------------#
  524. LIBS = sfml-graphics-s sfml-window-s sfml-system-s freetype png jpeg bz2 \
  525.                 zlibstatic PocoUtil PocoFoundation opengl32 gdi32 winmm Iphlpapi ws2_32 uuid
  526.  
  527. ifeq ($(CONFIG),tests)  
  528. LIBS += cppunit
  529. endif
  530.  
  531.  
  532.  
  533.  
  534. # Arquivos
  535. #----------------------------------------------------------------#
  536. ifeq ($(CONFIG),tests)
  537. SOURCE = $(call rfind,$(PROJECT_SRC)/ph,*.cpp)
  538. SOURCE += $(call rfind,$(PROJECT_TESTS),*.cpp)
  539. SOURCE := $(filter-out %/winmain.cpp,$(SOURCE))
  540. else
  541. SOURCE = $(call rfind,$(PROJECT_SRC),*.cpp)
  542. endif
  543.  
  544. OBJS  = $(addprefix $(OBJS_DIR)/,$(notdir $(SOURCE:.cpp=.o)))
  545.  
  546.  
  547.  
  548.  
  549. # Nao modificar
  550. #----------------------------------------------------------------#
  551. CXX_LINK = $(CXX) $(CXXFLAGS) $(addprefix -L, $(PROJECT_LIB) $(SDK_LIB))
  552. CXX_COMPILE = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(addprefix -I, $(SDK_INC) $(ROOT) $(PROJECT_INC)) -c
  553.  
  554.  
  555. ifeq ($(CONFIG),tests)
  556. CXX_LINK+= -Wl,--subsystem,console
  557. CXX_COMPILE+= $(DEBUGFLAGS) $(TESTSFLAGS) -Wl,--subsystem,console
  558. endif
  559.  
  560. ifeq ($(CONFIG),debug)
  561. CXX_LINK+= -Wl,--subsystem,windows
  562. CXX_COMPILE+= $(DEBUGFLAGS) -Wl,--subsystem,windows
  563. endif
  564.  
  565. ifeq ($(CONFIG),release)
  566. CXX_LINK+= -Wl,--subsystem,windows
  567. CXX_COMPILE+= $(RELEASEFLAGS) -Wl,--subsystem,windows
  568. endif
  569.  
  570.  
  571. EXE := $(CONFIG_DIR)/$(EXE)
  572.  
  573.  
  574.  
  575.  
  576. # Regras
  577. #----------------------------------------------------------------#
  578.  
  579. .PHONY: all debug tests objs
  580.  
  581.  
  582. .dirs:
  583.         @if not exist $(subst /,\,$(OBJS_DIR)) $(MKDIR) $(subst /,\,$(OBJS_DIR))
  584.    
  585.  
  586. .$(CONFIG)-pre:
  587.  
  588.  
  589. $(CONFIG): .$(CONFIG)-pre .dirs $(EXE)
  590.         @echo -
  591.         @echo [  OK  ] $@
  592.         @echo -
  593.    
  594.        
  595. clean-$(CONFIG):
  596.         @if exist $(CONFIG_DIR) $(RM) $(subst /,\,$(CONFIG_DIR))
  597.         @echo Clean $(CONFIG) done.
  598.    
  599.  
  600. clean-all:
  601.         @if exist $(BUILD_DIR) $(RM) $(BUILD_DIR)
  602.         @echo Clean ALL done.
  603.        
  604.        
  605. clean: clean-all
  606.  
  607.  
  608.  
  609.  
  610. # Regras para construcao de executaveis.
  611. #----------------------------------------------------------------#
  612. $(EXE): $(OBJS)
  613. ifeq ($(VERBOSE),yes)
  614.         $(CXX_LINK) -o $@ $(OBJS) $(addprefix -l, $(LIBS))
  615. else
  616.         @$(CXX_LINK) -o $@ $(OBJS) $(addprefix -l, $(LIBS))
  617. endif
  618.  
  619.  
  620.  
  621.  
  622. # Regras para construcao de arquivos objeto.
  623. #----------------------------------------------------------------#
  624. $(OBJS): $(SOURCE)
  625.  
  626.  
  627. [% FOREACH path IN paths %]
  628. $(OBJS_DIR)/%.o:[% " " %]
  629.     [%- FILTER collapse %]
  630.                 [% IF path.length == 0 %]
  631.                         $(PROJECT_SRC)/%.cpp
  632.                 [% ELSE %]
  633.                         $(PROJECT_SRC)/[% path %]/%.cpp
  634.                 [% END %]
  635.     [% END %]
  636. ifeq ($(VERBOSE),yes)
  637.         $(CXX_COMPILE) $< -o $@
  638. else
  639.         @$(CXX_COMPILE) $< -o $@
  640. endif
  641.         @echo [  OK  ] $@
  642. [% END %]
  643.  
  644.  
  645.  
  646. [% FOREACH path IN testpaths %]
  647. $(OBJS_DIR)/%.o:[% " " %]
  648.     [%- FILTER collapse %]
  649.                 [% IF path.length == 0 %]
  650.                         $(PROJECT_TESTS)/%.cpp
  651.                 [% ELSE %]
  652.                         $(PROJECT_TESTS)/[% path %]/%.cpp
  653.                 [% END %]
  654.     [% END %]
  655. ifeq ($(VERBOSE),yes)
  656.         $(CXX_COMPILE) $< -o $@
  657. else
  658.         @$(CXX_COMPILE) $< -o $@
  659. endif
  660.         @echo [  OK  ] $@
  661. [% END %]
  662.  
  663.  
  664.  
  665. [% FOREACH file IN files %]
  666. $(OBJS_DIR)/[% file.name %]:[% " " %]
  667.     [%- FILTER collapse %]
  668.         [% FOREACH src IN file.dep_src %]
  669.             [% src %]
  670.         [% END %]
  671.         [% " " %]
  672.         [% FOREACH obj IN file.dep_obj %]
  673.             $(OBJS_DIR)/[% obj %]
  674.         [% END %]
  675.     [% END -%]
  676. [% END %]
  677.  
  678.  
  679.  
  680. [% FOREACH file IN testfiles %]
  681. $(OBJS_DIR)/[% file.name %]:[% " " %]
  682.     [%- FILTER collapse %]
  683.         [% FOREACH src IN file.dep_src %]
  684.             [% src %]
  685.         [% END %]
  686.         [% " " %]
  687.         [% FOREACH obj IN file.dep_obj %]
  688.             $(OBJS_DIR)/[% obj %]
  689.         [% END %]
  690.     [% END -%]
  691. [% END %]