use strict;
use warnings;
use Template;
use File::Find;
use Data::Dumper;
###############################################################################
# CONFIGURATION
###############################################################################
my $SOURCE = "./src";
my $TESTS = "./tests";
my $CONFIG = "";
if ((lc $ARGV[0]) =~ m/debug/)
{
$CONFIG = "debug";
}
elsif ((lc $ARGV[0]) =~ m/tests/)
{
$CONFIG = "tests";
}
###############################################################################
# Global vars
###############################################################################
my @PATHS;
my @CATALOG;
my @OBJECTS;
my @TESTPATHS;
my @TESTOBJECTS;
my $indent = 0;
###############################################################################
# Main
###############################################################################
{
my $tmp;
my $objfile;
my $srcfile;
puts("Starting scanning...");
$indent++;
find(\&find_files, $SOURCE);
find(\&find_files, $TESTS) if $CONFIG eq "tests";
$indent--;
change_path_from_win_2_unix();
foreach my $file(@CATALOG)
{
next if $file->{name} =~ m/\.o$/;
puts("Looking for " . $file->{name} . "'s dependencies.");
$indent++;
create_dependency_list(\$file);
$indent--;
}
foreach my $file(@CATALOG)
{
my @SRCLIST;
my @OBJLIST;
my @DEPENDENCYLIST;
$srcfile = $file->{name};
next if $srcfile !~ m/\.cpp$/;
$objfile = $srcfile;
$objfile =~ s/^.+\///;
$objfile =~ s/\.cpp$/.o/;
$indent++;
my @deps = @{ getDependencies(\$file) };
foreach my $itDep(@deps)
{
$tmp = $$itDep->{name};
if ($tmp =~ m/\.h$/)
{
$tmp =~ s/\.h$/.cpp/;
if (not $tmp eq $srcfile and -e $tmp)
{
$tmp =~ s/\.cpp$/.o/;
$tmp =~ s/^.+\///;
}
else
{
$tmp =~ s/\.cpp$/.h/;
}
}
push @SRCLIST, $tmp if $tmp =~ m/\.h$/;
push @OBJLIST, $tmp if $tmp =~ m/\.o$/;
my $found = 0;
if($file->{name} =~ m/^\.\/tests/)
{
foreach my $it(@TESTOBJECTS)
{
if($it->{name} eq $objfile)
{
$found = 1;
last;
}
}
push @TESTOBJECTS, { name
=> $objfile, dep_obj
=> \@OBJLIST, dep_src
=> \@SRCLIST } if not $found;
}
else
{
foreach my $it(@OBJECTS)
{
if($it->{name} eq $objfile)
{
$found = 1;
last;
}
}
push @OBJECTS, { name
=> $objfile, dep_obj
=> \@OBJLIST, dep_src
=> \@SRCLIST } if not $found;
}
}
$indent--;
}
{
makemake();
}
print "\n\nUpdating Makefile...\n\n";
}
sub change_path_from_win_2_unix
{
my $str = "";
foreach my $file(@CATALOG)
{
next if $file->{name} =~ m/\.o$/;
my $changed = 0;
open(my $HFILE, "<", $file->{name
}) or die "Cant open file " . $file->{name
} . ": $!\n";
my @lines = <$HFILE>;
foreach my $it(@lines)
{
next if $it !~ m/^(\s|\t)*#(\s|\t)*include/;
if ($it =~ m/\\/)
{
$it =~ s/\\/\//g;
$changed = 1;
}
}
if ($changed)
{
puts("Updating file: " . $file->{name});
open(my $HFILE, ">", $file->{name
}) or die "Cant open file " . $file->{name
} . ": $!\n";
foreach my $it(@lines)
{
}
}
}
}
sub getDependencies
{
my @aux;
if (defined $$self->{dependencies
})
{
my @dependencies = @{ $$self->{dependencies} };
push @aux, @dependencies;
foreach my $itDep(@dependencies)
{
my @tmp = @{ getDependencies($itDep) };
foreach my $itTmp(@tmp)
{
push @aux, $itTmp if not registered
(\@aux, $itTmp);
}
}
}
else
{
puts($$self->{name} . " has no dependencies.");
}
}
sub registered
{
my $reg = 0;
my ($refList, $refFile) = @_;
foreach my $it(@$refList)
{
{
if ($$refFile->{id} == $$it->{id})
{
$reg = 1;
last;
}
}
}
}
###############################################################################
#
###############################################################################
sub find_files
{
my @cppdep;
my @objdep;
my $cppfile;
my $objfile;
my $fname = $File::Find::name;
if (-d)
{
if($fname =~ m/^$TESTS/)
{
$fname =~ s/^$TESTS//;
foreach my $path(@TESTPATHS)
{
}
$fname =~ s/^(\/|\\)//;
}
elsif($fname =~ m/^$SOURCE/)
{
$fname =~ s/^$SOURCE//;
foreach my $path(@PATHS)
{
}
$fname =~ s/^(\/|\\)//;
}
puts("Adding path: " . $_);
}
elsif (m/\.(h|cpp)$/)
{
$fname = $File::Find::name;
$fname =~ s/^\.\///;
puts("Acquiring file " . $fname);
$indent++;
if ($fname =~ m/\.cpp$/)
{
$cppfile = { id => $id, name => $fname, dependencies => \@cppdep };
$id++;
$fname =~ s/\.cpp$/.o/;
puts("Creating object file: " . $fname);
$objfile = { id => $id, name => $fname, dependencies => \@objdep };
}
else
{
$cppfile = { id => $id, name => $fname, dependencies => \@cppdep };
}
$indent--;
}
}
###############################################################################
#
###############################################################################
sub create_dependency_list
{
my @dependencies;
my $dp;
$file = $$file;
my $filename = $file->{name};
open(my $HFILE, "<", $filename) or die "Cant open " . $filename . ": $!\n";
puts("Parsing " . $filename);
while (<$HFILE>)
{
next if not m/^(\s|\t)*#(\s|\t)*include(\s|\t)+".+"/;
s/^[^"]+"|"[^"]*$//g;
puts("Searching the catalog...");
$indent++;
my $refDependency = get_dependency_from_catalog($_);
next unless defined $refDependency;
@dependencies = @{ $file->{dependencies} };
push @dependencies, $refDependency;
$file->{dependencies} = \@dependencies;
$indent--;
}
}
###############################################################################
#
###############################################################################
sub get_dependency_from_catalog
{
foreach my $file(@CATALOG)
{
my $f2 = lc $file->{name
};
next if $f1 !~ m/$f2$/;
puts("Found dependency: " . $file->{name});
}
puts("*** Not in the catalog: " . $filename);
}
###############################################################################
#
###############################################################################
sub puts
{
for(my $i = 0; $i < $indent; $i++)
{
}
print "($indent) $msg\n";
}
###############################################################################
#
###############################################################################
sub makemake
{
my $makefile = "";
my $template = "";
my $tt = new Template({EVAL_PERL=>1});
while (<DATA>)
{
$template .= $_;
}
my $content = { cfg => $CONFIG, paths => \@PATHS, files => \@OBJECTS, testpaths => \@TESTPATHS, testfiles => \@TESTOBJECTS };
$tt->process(\$template, $content, \$makefile) or die $tt->error();
open(my $HFILE, ">", "Makefile") or die "Cant open file 'Makefile': $!\n";
#print $makefile;
}
__DATA__
#
# MAKEFILE GERADO AUTOMATICAMENTE.asdf
#
#---------------------------------------------------------------
# CONFIGURAÇÕES DE MONTAGEM
#---------------------------------------------------------------
# Nome do arquivo executavel para qualquer configuracao: debug, release, testes
EXE = ph.exe
# Configuracao utilizada para construir o programa.
# Por convencao, o programa final e os arquivos objeto sao copiados para o diretório build/$(CONFIG)/
CONFIG = [% cfg %]
# Define a menor versao do windows que deve ser suportada pelo programa.
WINVERSION = 0x501
# Auto explicativo.
BITNESS = 32
# Define o modo como as bibliotecas serao inseridas no programa.
# Valores validos: static, dynamic
LINKMODE = static
#
#
VERBOSE = yes
#---------------------------------------------------------------
# FIM
#---------------------------------------------------------------
# Funcoes
#----------------------------------------------------------------#
rfind=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rfind,$d/,$2))
# Definicao das ferramentas de compilacao, montagem e assistencia
#----------------------------------------------------------------#
CXX = g++
CP = sfk -yes copy
RM = sfk -yes deltree
SHELL = $(ComSpec)
# Flags
#----------------------------------------------------------------#
TESTSFLAGS = -DTESTS
DEBUGFLAGS = -g -O0 -DDEBUG
CPPFLAGS = -DWINVER=$(WINVERSION) -DUNICODE -DSFML_STATIC -DPOCO_STATIC
CXXFLAGS
= -Wall
-fmessage
-length=0 -std
=c
++11 -static
-static
-libgcc
-mms
-bitfields
-m$
(BITNESS
)
# Diretorios
#----------------------------------------------------------------#
ROOT ?= .
PROJECT_INC = $(ROOT)/include
PROJECT_SRC = $(ROOT)/src
PROJECT_LIB = $(ROOT)/lib
PROJECT_BIN = $(ROOT)/bin
PROJECT_TESTS = $(ROOT)/tests
SDK_ROOT ?= c:/sdk
SDK_INC = $(SDK_ROOT)/include
SDK_LIB = $(SDK_ROOT)/lib
SDK_BIN = $(SDK_ROOT)/bin
BUILD_DIR = $(ROOT)/build
CONFIG_DIR = $(BUILD_DIR)/$(CONFIG)
OBJS_DIR = $(CONFIG_DIR)/obj
# Bibliotecas
#----------------------------------------------------------------#
LIBS
= sfml
-graphics
-s sfml
-window
-s sfml
-system
-s freetype png jpeg bz2 \
zlibstatic PocoUtil PocoFoundation opengl32 gdi32 winmm Iphlpapi ws2_32 uuid
ifeq ($(CONFIG),tests)
LIBS += cppunit
endif
# Arquivos
#----------------------------------------------------------------#
ifeq ($(CONFIG),tests)
SOURCE = $(call rfind,$(PROJECT_SRC)/ph,*.cpp)
SOURCE += $(call rfind,$(PROJECT_TESTS),*.cpp)
SOURCE := $(filter-out %/winmain.cpp,$(SOURCE))
else
SOURCE = $(call rfind,$(PROJECT_SRC),*.cpp)
endif
OBJS = $(addprefix $(OBJS_DIR)/,$(notdir $(SOURCE:.cpp=.o)))
# Nao modificar
#----------------------------------------------------------------#
CXX_LINK = $(CXX) $(CXXFLAGS) $(addprefix -L, $(PROJECT_LIB) $(SDK_LIB))
CXX_COMPILE = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(addprefix -I, $(SDK_INC) $(ROOT) $(PROJECT_INC)) -c
ifeq ($(CONFIG),tests)
CXX_LINK+= -Wl,--subsystem,console
CXX_COMPILE+= $(DEBUGFLAGS) $(TESTSFLAGS) -Wl,--subsystem,console
endif
ifeq ($(CONFIG),debug)
CXX_LINK+= -Wl,--subsystem,windows
CXX_COMPILE+= $(DEBUGFLAGS) -Wl,--subsystem,windows
endif
ifeq ($(CONFIG),release)
CXX_LINK+= -Wl,--subsystem,windows
CXX_COMPILE+= $(RELEASEFLAGS) -Wl,--subsystem,windows
endif
EXE := $(CONFIG_DIR)/$(EXE)
# Regras
#----------------------------------------------------------------#
.PHONY: all debug tests objs
.dirs:
@if not exist $(subst /,\,$(OBJS_DIR)) $(MKDIR) $(subst /,\,$(OBJS_DIR))
.$(CONFIG)-pre:
$(CONFIG): .$(CONFIG)-pre .dirs $(EXE)
@echo -
@echo [ OK ] $@
@echo -
clean-$(CONFIG):
@if exist $(CONFIG_DIR) $(RM) $(subst /,\,$(CONFIG_DIR))
@echo Clean $(CONFIG) done.
clean-all:
@if exist $(BUILD_DIR) $(RM) $(BUILD_DIR)
@echo Clean ALL done.
clean: clean-all
# Regras para construcao de executaveis.
#----------------------------------------------------------------#
$(EXE): $(OBJS)
ifeq ($(VERBOSE),yes)
$(CXX_LINK) -o $@ $(OBJS) $(addprefix -l, $(LIBS))
else
@$(CXX_LINK) -o $@ $(OBJS) $(addprefix -l, $(LIBS))
endif
# Regras para construcao de arquivos objeto.
#----------------------------------------------------------------#
$(OBJS): $(SOURCE)
[% FOREACH path IN paths %]
$(OBJS_DIR)/%.o:[% " " %]
[%- FILTER collapse %]
$(PROJECT_SRC)/%.cpp
[% ELSE %]
$(PROJECT_SRC)/[% path %]/%.cpp
[% END %]
[% END %]
ifeq ($(VERBOSE),yes)
$(CXX_COMPILE) $< -o $@
else
@$(CXX_COMPILE) $< -o $@
endif
@echo [ OK ] $@
[% END %]
[% FOREACH path IN testpaths %]
$(OBJS_DIR)/%.o:[% " " %]
[%- FILTER collapse %]
$(PROJECT_TESTS)/%.cpp
[% ELSE %]
$(PROJECT_TESTS)/[% path %]/%.cpp
[% END %]
[% END %]
ifeq ($(VERBOSE),yes)
$(CXX_COMPILE) $< -o $@
else
@$(CXX_COMPILE) $< -o $@
endif
@echo [ OK ] $@
[% END %]
[% FOREACH file IN files %]
$(OBJS_DIR)/[% file.name %]:[% " " %]
[%- FILTER collapse %]
[% FOREACH src IN file.dep_src %]
[% src %]
[% END %]
[% " " %]
[% FOREACH obj IN file.dep_obj %]
$(OBJS_DIR)/[% obj %]
[% END %]
[% END -%]
[% END %]
[% FOREACH file IN testfiles %]
$(OBJS_DIR)/[% file.name %]:[% " " %]
[%- FILTER collapse %]
[% FOREACH src IN file.dep_src %]
[% src %]
[% END %]
[% " " %]
[% FOREACH obj IN file.dep_obj %]
$(OBJS_DIR)/[% obj %]
[% END %]
[% END -%]
[% END %]