This commit is contained in:
John M. Penn 2023-02-01 14:46:42 -06:00
commit 917cd84dfc
21 changed files with 289 additions and 52 deletions

View File

@ -9,6 +9,7 @@ on:
- '.github/workflows/**'
- '!.github/workflows/code_coverage.yml'
pull_request:
workflow_dispatch:
jobs:
code-coverage:

View File

@ -8,3 +8,4 @@ Link documentation for Trick internals, processes, and plans here.
- [Testing](Testing)
- [How to make a new Trick release on GitHub](How-To-Make-A-Release)
- [Tooling and Sanitizers](Tooling-and-Sanitizers)

View File

@ -0,0 +1,35 @@
| [Home](/trick) → [Developer Docs](Developer-Docs-Home) → Tooling and Sanitizers |
|------------------------------------------------------------------|
Lots of development and debugging tools require a binary to be instrumented with compiler flags. Trick does compiling and linking steps separately and uses several variables to propogate flags to different parts of the build. The following is a convenience function that can be added to your bashrc to easily modify the flags in your environment:
```
add-trickenv () {
export CFLAGS="$CFLAGS $1"
export CXXFLAGS="$CXXFLAGS $1"
export LDFLAGS="$LDFLAGS $1"
export TRICK_CFLAGS="$TRICK_CFLAGS $1"
export TRICK_CXXFLAGS="$TRICK_CXXFLAGS $1"
export TRICK_LDFLAGS="$TRICK_LDFLAGS $1"
export TRICK_SYSTEM_CFLAGS="$TRICK_SYSTEM_CFLAGS $1"
export TRICK_SYSTEM_CXXFLAGS="$TRICK_SYSTEM_CXXFLAGS $1"
export TRICK_SYSTEM_LDFLAGS="$TRICK_SYSTEM_LDFLAGS $1"
}
```
To debug a sim, you will likely need to run a clean build of all of Trick with these flags set.
## Tools that are known to work well with Trick
GDB/LLDB: `-g`
gcov: `-fprofile-arcs -ftest-coverage -O0`
tsan: `-g -fsanitize=thread`
asan: `-g -fsanitize=address -fsanitize-recover=address`
Suggest running asan instrumented sims with:
`ASAN_OPTIONS=halt_on_error=0 ./S_main* <your args>`

View File

@ -162,7 +162,7 @@ The `ICG IGNORE TYPES` field lists the structs or classes to be ignored. Any par
###### `PYTHON_MODULE`
Specifying a `python_module` name will place any class/struct and function definitions in this header file in a python module of the same name. All classes and functions are flattened into the python `trick` namespace by default. This capability allows users to avoid possible name collisions between names when they are flattened.
Specifying a `python_module` name will place any class/struct and function definitions in this header file in a python module of the same name. All classes and functions are flattened into the python `trick` namespace by default. This capability allows users to avoid possible name collisions between names when they are flattened. An empty `python_module` statement will be ignored.
##### Compiler Directives

View File

@ -449,6 +449,9 @@ For information on how Trick processes events during runtime, see [Event Process
# Add the event to the input processor's list of events (it will be processed at top of frame before scheduled jobs)
trick.add_event(<event name>)
# Tell trick whether to terminate the sim if an error occurs while parsing Python code. Defaults to False
trick.terminate_on_event_parse_error(<True|False>)
```
#### Advanced Event (Malfunction) Usage

View File

@ -184,6 +184,15 @@ namespace Trick {
*/
static void set_event_info_msg_off() ;
/**
@brief @userdesc Command to set whether the sim should check error codes from
Python parsing and terminate if an error is detected. Set to false by default
@par Python Usage:
@code trick.terminate_on_event_parse_error(True|False) @endcode
@return always 0
*/
static void terminate_on_event_parse_error(bool on_off);
/**
@brief called by the event manager when the event is loaded from a checkpoint
*/
@ -402,7 +411,7 @@ namespace Trick {
any events instantiated yet */
static void set_python_processor(Trick::IPPython * in_ip) ;
static void set_mtv(Trick::MTV * in_mtv) ;
private:
/* A static pointer to the python input processor set at the S_define level */
@ -411,6 +420,8 @@ namespace Trick {
/* A static pointer to the MTV set at the S_define level */
static Trick::MTV * mtv ;
/* Defaults to false */
static bool terminate_sim_on_event_python_error;
} ;
}

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

@ -44,6 +44,7 @@ if hasattr(top.cvar, 'trick_ip'):
set_event_info_msg_on = trick.IPPythonEvent.set_event_info_msg_on
set_event_info_msg_off = trick.IPPythonEvent.set_event_info_msg_off
terminate_on_event_parse_error = trick.IPPythonEvent.terminate_on_event_parse_error
# bind pyton input_processor event routines to shortcut names.
new_event = trick.ippython_new_event

View File

@ -0,0 +1,7 @@
trick.stop(1.0)
# print(dir(trick))
trick.terminate_on_event_parse_error(True)
# Error in add read
trick.add_read(0.1, "a = b")

View File

@ -0,0 +1,12 @@
trick.terminate_on_event_parse_error(True)
# Error in condition
event1 = trick.new_event("event1")
event1.condition(0, "this is a syntax error")
event1.action(0, "print (\"event1\");")
event1.action(1, "event1.activate()")
event1.set_cycle(1.0)
event1.activate()
trick.add_event(event1)
trick.stop(10)

View File

@ -0,0 +1,12 @@
trick.terminate_on_event_parse_error(True)
# Error in event action
event1 = trick.new_event("event1")
event1.condition(0, "True")
event1.action(0, "this is a syntax error")
event1.action(1, "event1.activate()")
event1.set_cycle(1.0)
event1.activate()
trick.add_event(event1)
trick.stop(10)

View File

@ -43,6 +43,13 @@ def main():
yummy.yummy = trick.Foo.Doughnuts
TRICK_EXPECT_EQ( yummy.yummy , 2, test_suite , "additional file in same namespace" )
# new class from TrickFood
trickfood = trick.Food()
trickfood.print_me()
TRICK_EXPECT_EQ( trickfood.fast , 2, test_suite , "blank python_module statement" )
trickfood.fast = trick.Pizza
TRICK_EXPECT_EQ( trickfood.fast , 0, test_suite , "blank python_module statement" )
if __name__ == "__main__":
main()

View File

@ -1,6 +1,6 @@
/************************TRICK HEADER*************************
PURPOSE:
(blah blah blah)
(Test different combinations of Python modules and C++ namespaces)
*************************************************************/
#include "sim_objects/default_trick_sys.sm"
@ -9,6 +9,7 @@ PURPOSE:
##include "FooInnerFood.hh"
##include "BarFood.hh"
##include "FooYummyFood.hh"
##include "TrickFood.hh"
class SimObj : public Trick::SimObject {
@ -17,6 +18,7 @@ class SimObj : public Trick::SimObject {
Foo::Inner::Food foo_inner_food ;
Bar::Food bar_food ;
Foo::YummyFood foo_yummyfood ;
Food trick_food;
/** Constructor to add the jobs */
SimObj() {

View File

@ -0,0 +1,32 @@
/**
@file
@verbatim
PURPOSE: (Test that an empty PYTHON_MODULE won't cause errors or have any effect.)
PYTHON_MODULE: ()
@endverbatim
*******************************************************************************/
#ifndef TRICKFOOD_HH
#define TRICKFOOD_HH
#include <iostream>
enum Fast {
Pizza,
Burger,
Taco
};
class Food {
public:
Food() : fast(Taco) {}
void print_me() { std::cout << "Food::print_me!" << std::endl; }
Fast fast;
};
#endif

View File

@ -42,13 +42,6 @@ SIM_demo_sdefine:
runs:
RUN_test/unit_test.py:
returns: 0
SIM_events:
path: test/SIM_events
build_command: "trick-CP -t"
binary: "T_main_{cpu}_test.exe"
runs:
RUN_test/unit_test.py:
returns: 0
SIM_exec_set_time_tic_value:
path: test/SIM_exec_set_time_tic_value
build_command: "trick-CP -t"
@ -267,6 +260,21 @@ SIM_checkpoint_data_recording:
# compare:
# - test/SIM_checkpoint_data_recording/RUN_test6/ref_log_foo2.csv vs. test/SIM_checkpoint_data_recording/RUN_test6/log_foo2.csv
SIM_events:
path: test/SIM_events
build_command: "trick-CP -t"
binary: "T_main_{cpu}_test.exe"
runs:
RUN_test/unit_test.py:
returns: 0
RUN_test/unit_test_error1.py:
returns: 255
RUN_test/unit_test_error2.py:
returns: 255
RUN_test/unit_test_error3.py:
returns: 255
# The variable server client and SIM_amoeba sometimes fail to connect and need to be retried
SIM_test_varserv:
path: test/SIM_test_varserv

View File

@ -11,7 +11,7 @@ dyn.aircraft.desired_speed = 200 # meters per second
# Start the Satellite Graphics Client
#==========================================
varServerPort = trick.var_server_get_port();
AircraftDisplay_path = "models/graphics/dist/AircraftDisplay.jar"
AircraftDisplay_path = "models/graphics/build/AircraftDisplay.jar"
if (os.path.isfile(AircraftDisplay_path)) :
AircraftDisplay_cmd = "java -jar " \

36
trick_sims/SIM_aircraft/models/graphics/Makefile Normal file → Executable file
View File

@ -1,36 +1,6 @@
SHELL = /bin/sh
PROJECT_NAME = AircraftDisplay
SRC_DIR = src
BUILD_DIR = build
CLASSES_DIR = $(BUILD_DIR)/classes
JAR_DIR = dist
MAIN_CLASS = trick.AircraftDisplay
all: jar
all:
mvn package
clean:
rm -rf $(BUILD_DIR)
rm -f manifest
spotless: clean
rm -rf dist
$(CLASSES_DIR):
@ mkdir -p $(CLASSES_DIR)
compile: | $(CLASSES_DIR)
javac -sourcepath $(SRC_DIR) -d $(CLASSES_DIR) $(SRC_DIR)/trick/AircraftDisplay.java
manifest:
@ echo "Main-Class: $(MAIN_CLASS)" > $@
$(JAR_DIR):
@ mkdir -p $(JAR_DIR)
jar: compile manifest | $(JAR_DIR)
jar cvfm $(JAR_DIR)/$(PROJECT_NAME).jar manifest -C $(CLASSES_DIR) .
@ echo "-------------------------------------------------------------------------------"
@ echo " BUILD COMPLETE"
@ echo "The Java jar file (the Java Executable) is located at: $(JAR_DIR)/$(PROJECT_NAME).jar"
@ echo "-------------------------------------------------------------------------------"
rm -rf build

View File

@ -0,0 +1,121 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>trick-java</groupId>
<artifactId>trick-java</artifactId>
<version>23.0.0-beta</version>
<name>trick-java</name>
<url>https://github.com/nasa/trick</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>AircraftDisplay</finalName>
<directory>build</directory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>
<destDir>../../share/doc/trick/java</destDir>
</configuration>
</plugin>
</plugins>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<compilerArgs>
<arg>-g</arg>
<arg>-Xlint:unchecked</arg>
<arg>-Xlint:deprecation</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<!-- Build an executable JAR -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>AircraftDisplay</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<!--
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
-->
</plugins>
</pluginManagement>
</build>
</project>

View File

@ -3,7 +3,7 @@
* 2016 (c) National Aeronautics and Space Administration (NASA)
*/
package trick;
/* package trick;*/
import java.awt.Graphics2D;
import java.awt.Graphics;

View File

@ -179,11 +179,11 @@ int Trick::IPPython::parse_condition(std::string in_string, int & cond_return_va
pthread_mutex_lock(&ip_mutex);
in_string = std::string("trick_ip.ip.return_val = ") + in_string + "\n" ;
// Running the simple string will set return_val.
PyRun_SimpleString(in_string.c_str()) ;
int py_ret = PyRun_SimpleString(in_string.c_str()) ;
cond_return_val = return_val ;
pthread_mutex_unlock(&ip_mutex);
return 0 ;
return py_ret ;
}

View File

@ -29,6 +29,7 @@ extern Trick::MemoryManager * trick_MM ;
Trick::IPPython * Trick::IPPythonEvent::ip ;
Trick::MTV * Trick::IPPythonEvent::mtv ;
bool Trick::IPPythonEvent::info_msg = false ;
bool Trick::IPPythonEvent::terminate_sim_on_event_python_error = false;
Trick::condition_t::condition_t() {
enabled = 0 ;
@ -169,6 +170,10 @@ void Trick::IPPythonEvent::set_event_info_msg_off() {
info_msg = false;
}
void Trick::IPPythonEvent::terminate_on_event_parse_error(bool on_off) {
terminate_sim_on_event_python_error = on_off;
}
void Trick::IPPythonEvent::restart() {
int jj ;
@ -515,7 +520,10 @@ int Trick::IPPythonEvent::process( long long curr_time ) {
} else {
// it's a read event
active = false ;
ip->parse(action_list[0]->str) ;
int ret = ip->parse(action_list[0]->str) ;
if (ret != 0 && terminate_sim_on_event_python_error) {
exec_terminate_with_return( ret , __FILE__ , __LINE__ , "Python error in event processing" ) ;
}
// keep stats so mtv will show when it ran
fired_count++ ;
fired_time = curr_time ;
@ -572,7 +580,10 @@ bool Trick::IPPythonEvent::process_user_event( long long curr_time ) {
} else {
// otherwise use python to evaluate string
std::string full_in_string ;
ip->parse_condition(condition_list[ii]->str, return_val) ;
int python_ret = ip->parse_condition(condition_list[ii]->str, return_val) ;
if (python_ret != 0 && terminate_sim_on_event_python_error) {
exec_terminate_with_return( python_ret , __FILE__ , __LINE__ , "Python error in event condition processing" ) ;
}
}
if (return_val) {
//TODO: write to log/send_hs that trigger fired
@ -639,8 +650,11 @@ bool Trick::IPPythonEvent::process_user_event( long long curr_time ) {
break;
}
} else {
// otherwise use python to evaluate string
ip->parse(action_list[ii]->str) ;
// otherwise use python to evaluate string
int ret = ip->parse(action_list[ii]->str) ;
if (ret != 0 && terminate_sim_on_event_python_error) {
exec_terminate_with_return( ret , __FILE__ , __LINE__ , "Python error in event action processing" ) ;
}
}
it_ran = true ;
action_list[ii]->ran = true ;