diff --git a/libexec/trick/make_makefile_swig b/libexec/trick/make_makefile_swig index 364d9d40..a11b13b0 100755 --- a/libexec/trick/make_makefile_swig +++ b/libexec/trick/make_makefile_swig @@ -19,6 +19,9 @@ my @files_to_process ; my @ext_lib_files ; my %md5s ; my $verbose_build = exists($ENV{'TRICK_VERBOSE_BUILD'}) ; +my %trick_headers ; +my %python_modules ; +my %python_module_dirs ; sub get_paths { my @paths = split /:/ , $ENV{$_[0]} ; @@ -140,9 +143,21 @@ sub write_makefile_swig_deps() { close DEPENDENCIES_FILE ; } +sub get_trick_headers() { + foreach my $f ( @files_to_process, @ext_lib_files) { + my %trick_header = extract_trick_header( $f, do { local( @ARGV, $/ ) = $f ; <> }, 0, 0 ) ; + if ( exists $trick_header{python_module} ) { + $trick_headers{$f}{python_module} = $trick_header{python_module}; + ($trick_headers{$f}{python_module_dir} = $trick_header{python_module}) =~ s/\./\//g; + $python_modules{$trick_headers{$f}{python_module}} = 1; + $python_module_dirs{$trick_headers{$f}{python_module_dir}} = 1; + } + $trick_headers{$f}{swig} = $trick_header{swig} if ( exists $trick_header{swig} ); + } +} + sub has_swig_no($) { - my %trick_header = extract_trick_header( $_[0], do { local( @ARGV, $/ ) = $_[0] ; <> }, 0, 0 ) ; - my $result = $trick_header{swig} =~ /^NO$/i ; + my $result = $trick_headers{$_[0]}{swig} =~ /^NO$/i ; print "SWIG Skip SWIG: (NO): $_[0]\n" if $verbose_build and $result ; return $result ; } @@ -204,10 +219,25 @@ all: \$(TRICK_FIXED_PYTHON) SWIG_I =" ; foreach my $file ( @files_to_process ) { - (my $swig_file = $file) =~ s/\.[^.]*$/_py.i/ ; - print MAKEFILE " \\\n build$swig_file" ; - $swig_file =~ s/i$/o/ ; - print PY_LINK_LIST "build$swig_file\n" ; + if ( !exists $trick_headers{$file}{python_module_dir} ) { + (my $swig_file = $file) =~ s/\.[^.]*$/_py.i/ ; + print MAKEFILE " \\\n build$swig_file" ; + $swig_file =~ s/i$/o/ ; + print PY_LINK_LIST "build$swig_file\n" ; + } + } + + print MAKEFILE " + +SWIG_I_CUSTOM_OUTDIR =" ; + + foreach my $file ( @files_to_process ) { + if ( exists $trick_headers{$file}{python_module_dir} ) { + (my $swig_file = $file) =~ s/\.[^.]*$/_py.i/ ; + print MAKEFILE " \\\n build$swig_file" ; + $swig_file =~ s/i$/o/ ; + print PY_LINK_LIST "build$swig_file\n" ; + } } print MAKEFILE " @@ -234,9 +264,24 @@ SWIG_SRC = \$(subst .i,.cpp,\$(SWIG_I)) $swig_src_dir/top.cpp \t\@echo \$(SWIG) \$(TRICK_INCLUDE) \$(TRICK_DEFINES) \$(TRICK_VERSIONS) \$(TRICK_SWIG_FLAGS) -c++ -python -includeall -ignoremissing -w201,303,325,362,389,401,451 -outdir trick -o \$@ \$< >> \$(MAKE_OUT) \t\$(ECHO_CMD)\$(SWIG) \$(TRICK_INCLUDE) \$(TRICK_DEFINES) \$(TRICK_VERSIONS) \$(TRICK_SWIG_FLAGS) -c++ -python -includeall -ignoremissing -w201,303,325,362,389,401,451 -outdir trick -o \$@ \$< 2>&1 | \$(TEE) -a \$(MAKE_OUT) ; exit \$\${PIPESTATUS[0]} +SWIG_SRC_CUSTOM_OUTDIR = \$(subst .i,.cpp,\$(SWIG_I_CUSTOM_OUTDIR))\n" ; + + foreach my $file ( @files_to_process ) { + if ( exists $trick_headers{$file}{python_module_dir} ) { + (my $swig_file = $file) =~ s/\.[^.]*$/_py.i/ ; + (my $cpp_file = $file) =~ s/\.[^.]*$/_py.cpp/ ; + print MAKEFILE " +build$cpp_file : build$swig_file | trick/$trick_headers{$file}{python_module_dir} +\t\$(PRINT_SWIG) +\t\@echo \$(SWIG) \$(TRICK_INCLUDE) \$(TRICK_DEFINES) \$(TRICK_VERSIONS) \$(TRICK_SWIG_FLAGS) -c++ -python -includeall -ignoremissing -w201,303,325,362,389,401,451 -outdir trick/$trick_headers{$file}{python_module_dir} -o \$@ \$< >> \$(MAKE_OUT) +\t\$(ECHO_CMD)\$(SWIG) \$(TRICK_INCLUDE) \$(TRICK_DEFINES) \$(TRICK_VERSIONS) \$(TRICK_SWIG_FLAGS) -c++ -python -includeall -ignoremissing -w201,303,325,362,389,401,451 -outdir trick/$trick_headers{$file}{python_module_dir} -o \$@ \$< 2>&1 | \$(TEE) -a \$(MAKE_OUT) ; exit \$\${PIPESTATUS[0]}\n"; + } + } + + print MAKEFILE " # SWIG_OBJECTS ================================================================= -SWIG_OBJECTS = \$(subst .cpp,.o,\$(SWIG_SRC)) $swig_src_dir/init_swig_modules.o +SWIG_OBJECTS = \$(subst .cpp,.o,\$(SWIG_SRC)) \$(subst .cpp,.o,\$(SWIG_SRC_CUSTOM_OUTDIR)) $swig_src_dir/init_swig_modules.o \$(SWIG_OBJECTS): %.o: %.cpp \t\$(PRINT_COMPILE_SWIG) @@ -323,6 +368,9 @@ LINK_LISTS += \$(LD_FILELIST)build/py_link_list print INITFILE "import sys\n" ; print INITFILE "import os\n" ; print INITFILE "sys.path.append(os.getcwd() + \"/trick\")\n" ; + foreach my $dir ( keys %python_module_dirs ) { + print INITFILE "sys.path.append(os.getcwd() + \"/trick/$dir\")\n" ; + } print INITFILE "\n" ; print INITFILE "import _sim_services\n" ; @@ -335,12 +383,16 @@ LINK_LISTS += \$(LD_FILELIST)build/py_link_list foreach $f ( @files_to_process, @ext_lib_files ) { print INITFILE "# $f\n" ; - print INITFILE "import _m$md5s{$f}\n" ; print INITFILE "from m$md5s{$f} import *\n" ; print INITFILE "combine_cvars(all_cvars, cvar)\n" ; print INITFILE "cvar = None\n\n" ; } + foreach my $mod ( keys %python_modules ) { + print INITFILE "import trick.$mod\n" ; + } + + print INITFILE "\n" ; print INITFILE "# S_source.hh\n" ; print INITFILE "import _m${s_source_md5}\n" ; print INITFILE "from m${s_source_md5} import *\n\n" ; @@ -357,6 +409,17 @@ LINK_LISTS += \$(LD_FILELIST)build/py_link_list print INITFILE "cvar = all_cvars\n\n" ; close INITFILE ; + foreach my $dir ( keys %python_module_dirs ) { + system("mkdir -p trick/$dir"); + open MODULE_INITFILE, ">trick/$dir/__init__.py"; + foreach my $file ( @files_to_process ) { + if ( exists $trick_headers{$file}{python_module_dir} and $trick_headers{$file}{python_module_dir} eq $dir ) { + print MODULE_INITFILE "from m$md5s{$file} import *\n" ; + } + } + close MODULE_INITFILE; + } + return ; } @@ -366,6 +429,7 @@ LINK_LISTS += \$(LD_FILELIST)build/py_link_list read_files_to_process() ; write_makefile_swig_deps() ; +get_trick_headers() ; # Remove SWIG: (NO) files, but not before they're written to the dependency file. # If SWIG: (NO) is removed, Makefile_swig needs to be regenerated. purge_swig_no_files() ; diff --git a/libexec/trick/pm/html.pm b/libexec/trick/pm/html.pm index b4e5f326..86dac2b1 100644 --- a/libexec/trick/pm/html.pm +++ b/libexec/trick/pm/html.pm @@ -31,7 +31,7 @@ sub extract_trick_header($$$$) { $header{icg_ignore} = $2 if $trick_header =~ /ICG[ _]IGNORE[ _]TYPE(S)?:[^(]*(.*?)\)([A-Z _\t\n\r]+:|[ \t\n\r]*$)/si ; $header{swig} = $1 if $trick_header =~ /SWIG:[^(]*\((.*?)\)([A-Z _\t\n\r]+:|[ \t\n\r]*$)/si ; $header{default_data} = $1 if $trick_header =~ /DEFAULT[ _]DATA:[^(]*(.*?)\)([A-Z _\t\n\r]+:|[ \t\n\r]*$)/si ; - $header{python_module} = $1 if $trick_header =~ /PYTHON[ _]MODULE:[^(]*(.*?)\)([A-Z _\t\n\r]+:|[ \t\n\r]*$)/si ; + $header{python_module} = $1 if $trick_header =~ /PYTHON[ _]MODULE:[^(]*\((.*?)\)([A-Z _\t\n\r]+:|[ \t\n\r]*$)/si ; $header{programmers} = $1 if $trick_header =~ /PROGRAMMERS:[^(]*(.*?)\)([A-Z _\t\n\r]+:|[ \t\n\r]*$)/si ; $header{language} = $1 if $trick_header =~ /LANGUAGE:[^(]*(.*?)\)([A-Z _\t\n\r]+:|[ \t\n\r]*$)/si ; diff --git a/test/SIM_python_namespace/RUN_test/unit_test.py b/test/SIM_python_namespace/RUN_test/unit_test.py new file mode 100644 index 00000000..55ddb85b --- /dev/null +++ b/test/SIM_python_namespace/RUN_test/unit_test.py @@ -0,0 +1,41 @@ + +from trick.unit_test import * + +def main(): + trick.stop(1.0) + trick_utest.unit_tests.enable() + trick_utest.unit_tests.set_file_name( os.getenv("TRICK_HOME") + "/trick_test/SIM_python_namespace.xml" ) + trick_utest.unit_tests.set_test_name( "PythonNamespace" ) + test_suite = "python_namespace" + + # normal class methods from S_define + ball.foo_food.print_me() + ball.foo_inner_food.print_me() + ball.bar_food.print_me() + print + + # new class from Foo.Food + food = trick.Foo.Food() + food.print_me() + TRICK_EXPECT_EQ( food.fast , 0, test_suite , "first level python namespace" ) + food.fast = trick.Foo.Burger + TRICK_EXPECT_EQ( food.fast , 2, test_suite , "first level python namespace" ) + + # new class from Foo.Food.Inner + foodinner = trick.Foo.Inner.Food() + foodinner.print_me() + TRICK_EXPECT_EQ( foodinner.fast , 1, test_suite , "second level python namespace" ) + foodinner.fast = trick.Foo.Inner.Burger + TRICK_EXPECT_EQ( foodinner.fast , 0, test_suite , "second level python namespace" ) + + # new class from Foo.Food.Inner + bar = trick.Bar.Food() + bar.print_me() + TRICK_EXPECT_EQ( bar.fast , 2, test_suite , "another first level python namespace" ) + bar.fast = trick.Bar.Burger + TRICK_EXPECT_EQ( bar.fast , 1, test_suite , "another first level python namespace" ) + +if __name__ == "__main__": + main() + + diff --git a/test/SIM_python_namespace/S_define b/test/SIM_python_namespace/S_define new file mode 100644 index 00000000..cceef8c7 --- /dev/null +++ b/test/SIM_python_namespace/S_define @@ -0,0 +1,26 @@ +/************************TRICK HEADER************************* +PURPOSE: + (blah blah blah) +*************************************************************/ + +#include "sim_objects/default_trick_sys.sm" + +##include "FooFood.hh" +##include "FooInnerFood.hh" +##include "BarFood.hh" + +class SimObj : public Trick::SimObject { + + public: + Foo::Food foo_food ; + Foo::Inner::Food foo_inner_food ; + Bar::Food bar_food ; + + /** Constructor to add the jobs */ + SimObj() { + } +} ; + +// Instantiations +SimObj ball ; + diff --git a/test/SIM_python_namespace/S_overrides.mk b/test/SIM_python_namespace/S_overrides.mk new file mode 100644 index 00000000..27536a3b --- /dev/null +++ b/test/SIM_python_namespace/S_overrides.mk @@ -0,0 +1,4 @@ + +TRICK_CFLAGS += -I./models +TRICK_CXXFLAGS += -I./models + diff --git a/test/SIM_python_namespace/models/BarFood.hh b/test/SIM_python_namespace/models/BarFood.hh new file mode 100644 index 00000000..9947d31d --- /dev/null +++ b/test/SIM_python_namespace/models/BarFood.hh @@ -0,0 +1,33 @@ +/** +@file + +@verbatim +PURPOSE: (Namespace Test) +PYTHON_MODULE: (Bar) +@endverbatim +*******************************************************************************/ + +#ifndef BARFOOD_HH +#define BARFOOD_HH + +#include + +namespace Bar { + +enum Fast { + Pizza, + Burger, + Taco +}; + +class Food { + public: + Food() : fast(Taco) {} + void print_me() { std::cout << "Bar::Food::print_me!" << std::endl; } + Fast fast; +}; + +} + +#endif /* _BALL_HH_ */ + diff --git a/test/SIM_python_namespace/models/FooFood.hh b/test/SIM_python_namespace/models/FooFood.hh new file mode 100644 index 00000000..2502848a --- /dev/null +++ b/test/SIM_python_namespace/models/FooFood.hh @@ -0,0 +1,33 @@ +/** +@file + +@verbatim +PURPOSE: (Namespace Test) +PYTHON_MODULE: (Foo) +@endverbatim +*******************************************************************************/ + +#ifndef FOOFOOD_HH +#define FOOFOOD_HH + +#include + +namespace Foo { + +enum Fast { + Taco, + Pizza, + Burger +}; + +class Food { + public: + Food() : fast(Taco) {} + void print_me() { std::cout << "Foo::Food::print_me!" << std::endl; } + Fast fast; +}; + +} + +#endif /* _BALL_HH_ */ + diff --git a/test/SIM_python_namespace/models/FooInnerFood.hh b/test/SIM_python_namespace/models/FooInnerFood.hh new file mode 100644 index 00000000..1e0b1b02 --- /dev/null +++ b/test/SIM_python_namespace/models/FooInnerFood.hh @@ -0,0 +1,31 @@ +/** +@file + +@verbatim +PURPOSE: (Namespace Test) +PYTHON_MODULE: (Foo.Inner) +@endverbatim +*******************************************************************************/ + +#ifndef FOOINNERFOOD_HH +#define FOOINNERFOOD_HH + +namespace Foo { + namespace Inner { + enum Fast { + Burger, + Taco, + Pizza + }; + + class Food { + public: + Food() : fast(Taco) {} + void print_me() { std::cout << "Foo::Inner::Food::print_me!" << std::endl; } + Fast fast; + }; + } +} + +#endif /* _BALL_HH_ */ + diff --git a/test/makefile b/test/makefile index 13326e08..c110a529 100644 --- a/test/makefile +++ b/test/makefile @@ -5,6 +5,7 @@ export TRICK_HOST_CPU := $(shell $(TRICK_HOME)/bin/trick-gte TRICK_HOST_CPU) COMPILE_DIRS = \ SIM_demo_sdefine \ SIM_events \ + SIM_python_namespace \ SIM_rti \ SIM_stls \ SIM_test_dp \