Adding back a lost capability, but better this time. The user can now

specify a python module name where the class and functions will be
visible in python.  With care the user can mimic the C++ namespaces their
models reside in, but it isn't perfect nor automatic.  It's still pretty
neat.
This commit is contained in:
Alex Lin 2019-03-13 16:17:08 -05:00
parent be4372a831
commit 62948308b6
9 changed files with 242 additions and 9 deletions

View File

@ -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() ;

View File

@ -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 ;

View File

@ -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()

View File

@ -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 ;

View File

@ -0,0 +1,4 @@
TRICK_CFLAGS += -I./models
TRICK_CXXFLAGS += -I./models

View File

@ -0,0 +1,33 @@
/**
@file
@verbatim
PURPOSE: (Namespace Test)
PYTHON_MODULE: (Bar)
@endverbatim
*******************************************************************************/
#ifndef BARFOOD_HH
#define BARFOOD_HH
#include <iostream>
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_ */

View File

@ -0,0 +1,33 @@
/**
@file
@verbatim
PURPOSE: (Namespace Test)
PYTHON_MODULE: (Foo)
@endverbatim
*******************************************************************************/
#ifndef FOOFOOD_HH
#define FOOFOOD_HH
#include <iostream>
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_ */

View File

@ -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_ */

View File

@ -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 \