5 # Copyright The SCons Foundation
7 # Permission is hereby granted, free of charge, to any person obtaining
8 # a copy of this software and associated documentation files (the
9 # "Software"), to deal in the Software without restriction, including
10 # without limitation the rights to use, copy, modify, merge, publish,
11 # distribute, sublicense, and/or sell copies of the Software, and to
12 # permit persons to whom the Software is furnished to do so, subject to
13 # the following conditions:
15 # The above copyright notice and this permission notice shall be included
16 # in all copies or substantial portions of the Software.
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
19 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
20 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 Real-world test (courtesy Leanid Nazdrynau) of the multi-step
28 capabilities of the various Java Builders.
30 TODO: the whole Applet facility is deprecated, need a new test.
38 test
= TestSCons
.TestSCons()
40 where_javac
, java_version
= test
.java_where_javac()
41 where_javah
= test
.java_where_javah()
42 where_java_include
=test
.java_where_includes()
44 swig
= test
.where_is('swig')
46 test
.skip_test('Can not find installed "swig", skipping test.\n')
48 # Skip this test on AppVeyor
50 # Skip this test as SCons doesn't (currently) predict the generated
51 # inner/anonymous class generated .class files generated by gcj
52 # and so will always fail
54 test
.skip_test('Test not valid for gcj (gnu java); skipping test(s).\n')
56 # TODO rework for 'javac -h', for now skip
57 # The logical test would be: if java_version > 9:
58 # but java_where_javah() roots around and will find from an older version
59 if not test
.Environment().WhereIs('javah'):
60 test
.skip_test("No Java javah for version > 9, skipping test.\n")
62 # On some systems, the alternatives system does not remove javah even if the
63 # preferred Java doesn't have it, so try another check
64 javacdir
= pathlib
.Path(where_javac
).parent
65 javahdir
= pathlib
.Path(where_javah
).parent
66 if javacdir
!= javahdir
:
67 test
.skip_test("Cannot find Java javah matching javac, skipping test.\n")
71 ['src', 'HelloApplet'],
72 ['src', 'HelloApplet', 'com'],
76 ['src', 'server', 'JavaSource'],
77 ['src', 'server', 'JavaSource', 'com'],
78 ['src', 'server', 'JavaSource', 'com', 'gnu'],
79 ['src', 'server', 'JavaSource', 'com', 'gnu', 'scons'],
80 ['src', 'server', 'JavaSource', 'com', 'gnu', 'scons', 'web'],
81 ['src', 'server', 'JavaSource', 'com', 'gnu', 'scons', 'web', 'tools'],
82 ['src', 'server', 'WebContent'],
83 ['src', 'server', 'WebContent', 'META-INF'],
84 ['src', 'server', 'WebContent', 'WEB-INF'],
85 ['src', 'server', 'WebContent', 'WEB-INF', 'conf'],
86 ['src', 'server', 'WebContent', 'WEB-INF', 'lib'],
87 ['src', 'server', 'WebContent', 'theme'],
90 test
.write(['SConstruct'], """\
93 if sys.platform == 'win32':
94 # Ensure tests don't pick up link from mingw or cygwin
95 tools = ['msvc', 'mslink', 'jar', 'javac', 'javah', 'swig']
97 tools = ['default', 'javac', 'javah', 'swig']
99 _ = DefaultEnvironment(tools=[])
100 env = Environment(tools=tools, CPPPATH=["$JAVAINCLUDES"])
102 # env.PrependENVPath('PATH',os.environ.get('PATH',[]))
103 env['INCPREFIX'] = '-I'
104 env.Append(SWIGFLAGS=['-c++', '$_CPPINCFLAGS'])
107 # env.Append(CCFLAGS=['/IN:/jdk/v1.3.1/include','/IN:/jdk/v1.3.1/include/win32'])
109 # this for windows only C++ build
110 # env.Append(CXXFLAGS='-GX')
112 env.Append(CPPPATH='.')
114 env.VariantDir('buildout', 'src', duplicate=0)
116 if sys.platform[:6] == 'darwin':
117 env.Append(CPPPATH=['/System/Library/Frameworks/JavaVM.framework/Headers'])
119 # If you do not have swig on your system please remove
120 # 'buildout/jni/SConscript' line from next call
123 'buildout/server/JavaSource/SConscript',
124 'buildout/HelloApplet/SConscript',
125 'buildout/jni/SConscript',
126 'buildout/javah/SConscript',
131 test
.write(['src', 'HelloApplet', 'Hello.html'], """\
134 <TITLE> Applet Hello </TITLE>
138 <applet name="Hello" archive="HelloApplet.jar" code="com.Hello.Hello.class"
139 width="800" height="286" MAYSCRIPT>
147 test
.write(['src', 'HelloApplet', 'SConscript'], """\
152 classes = denv.Java(target='classes', source=['com'])
153 # set correct path for jar
154 denv['JARCHDIR'] = os.path.join(denv.Dir('.').get_abspath(), 'classes')
155 denv.Jar('HelloApplet', classes)
157 # To sign applet you have to create keystore before and made a calls like this
159 # keystore='/path/to/jarsignkey'
160 # denv['JARSIGNFLAGS']='-keystore '+keystore+' -storepass pass -keypass passkey'
161 # denv['JARSIGNALIAS']='ALIAS'
162 # denv['JARCOM']=[denv['JARCOM'],'$JARSIGNCOM']
165 test
.write(['src', 'HelloApplet', 'com', 'Hello.java'], """\
168 import java.applet.*;
170 public class Hello extends Applet {
171 static final long serialVersionUID = 0;
172 public void paint(Graphics g)
174 g.drawString("Hello from SCons signed applet",250,150);
179 test
.write(['src', 'javah', 'MyID.cc'], """\
182 __declspec(dllexport)
190 test
.write(['src', 'javah', 'MyID.java'], """\
193 static private long current = System.currentTimeMillis();
194 static public String get()
197 return new Long( current ).toString();
202 test
.write(['src', 'javah', 'SConscript'], """\
205 denv['JARCHDIR'] = denv.Dir('.').get_abspath()
206 denv.Jar('myid', 'MyID.java')
207 denv.JavaH(denv.Dir('.').get_abspath(), 'MyID.java')
208 denv.SharedLibrary('myid', 'MyID.cc')
211 test
.write(['src', 'jni', 'A.java'], """\
218 void echo2( String text )
220 System.out.println( text+"aa" );
226 void echo( String text )
228 System.out.println( text );
230 c.echo2("from B callin C");
233 public void main( String[] x)
243 test
.write(['src', 'jni', 'JniWrapper.cc'], """\
247 #include "JniWrapper.h"
249 JniWrapper::JniWrapper( JNIEnv *pEnv )
254 JniWrapper::JniWrapper( const JniWrapper& rJniWrapper )
255 : mpEnv( rJniWrapper.mpEnv )
259 JniWrapper::~JniWrapper()
263 JniWrapper& JniWrapper::operator=( const JniWrapper& rJniWrapper )
265 if ( this != &rJniWrapper )
267 mpEnv = rJniWrapper.mpEnv;
272 std::string JniWrapper::unmarshalString( jstring value )
277 const char *pStr = mpEnv->GetStringUTFChars( value, 0 );
279 mpEnv->ReleaseStringUTFChars( value, pStr );
284 jobject JniWrapper::marshalDouble( double value )
286 jclass classObject = mpEnv->FindClass( "java/lang/Double" );
287 jmethodID constructorId = mpEnv->GetMethodID( classObject, "<init>", "(D)V" );
288 jobject result = mpEnv->NewObject( classObject, constructorId, value );
293 jobject JniWrapper::getVectorElement( jobject values, int i )
295 jclass vectorClass = mpEnv->FindClass( "java/util/Vector" );
296 jmethodID methodID = mpEnv->GetMethodID( vectorClass,
298 "(I)Ljava/lang/Object;" );
299 jobject result = mpEnv->CallObjectMethod( values, methodID, i );
304 jobject JniWrapper::newVector()
306 jclass vectorClass = mpEnv->FindClass( "java/util/Vector" );
307 jmethodID constructorID = mpEnv->GetMethodID( vectorClass, "<init>", "()V" );
308 jobject result = mpEnv->NewObject( vectorClass, constructorID );
313 void JniWrapper::addElement( jobject vector, jobject element )
315 jclass vectorClass = mpEnv->FindClass( "java/util/Vector" );
316 jmethodID addElementMethodID = mpEnv->GetMethodID( vectorClass,
318 "(Ljava/lang/Object;)V" );
320 mpEnv->CallVoidMethod( vector, addElementMethodID, element );
323 jobject JniWrapper::marshalDoubleVector( const std::vector<double>& rVector )
325 jobject result = newVector();
327 for ( int i = 0; i < rVector.size(); i++ )
329 addElement( result, marshalDouble( rVector[i] ) );
335 std::pair<std::string, std::string> JniWrapper::unmarshalPairString( jobject vector )
337 std::pair<std::string, std::string> result;
338 result.first = unmarshalString( (jstring)getVectorElement( vector, 0 ) );
339 result.second = unmarshalString( (jstring)getVectorElement( vector, 1 ) );
345 test
.write(['src', 'jni', 'JniWrapper.h'], """\
351 * Provides routines for dealing with JNI translation etc.
357 JniWrapper( JNIEnv *pEnv );
358 JniWrapper( const JniWrapper& rJniWrapper );
359 virtual ~JniWrapper();
360 JniWrapper& operator=( const JniWrapper& rJniWrapper );
363 std::string unmarshalString( jstring value );
365 jstring marshalString( const std::string& value );
367 jbyteArray marshalByteArray( const std::string& value );
369 double unmarshalDouble( jobject value );
371 jobject marshalDouble( double value );
372 jobject marshallStringVector( const std::vector<std::string>& rMap );
374 jobject marshalDoubleVector( const std::vector<double>& rVector );
375 std::pair<std::string, std::string> unmarshalPairString( jobject );
383 void addElement( jobject vector, jobject element );
384 jobject getVectorElement( jobject values, int i );
388 #endif // JniWrapper_h
393 test
.write(['src', 'jni', 'SConscript'], """\
397 denv.Append(SWIGFLAGS=['-java'])
398 denv.SharedLibrary('scons', ['JniWrapper.cc', 'Sample.i'])
399 denv['JARCHDIR'] = denv.Dir('.').get_abspath()
400 denv.Jar(['Sample.i', 'A.java'])
403 test
.write(['src', 'jni', 'Sample.h'], """\
410 std::vector<double> test1( std::pair<std::string, std::string> param )
412 std::vector<double> result;
413 result.push_back(10);
420 test
.write(['src', 'jni', 'Sample.i'], """\
425 #include "JniWrapper.h"
428 %typemap(jni) std::vector<double>, std::vector<double>& "jobject"
429 %typemap(jtype) std::vector<double>, std::vector<double>& "java.util.Vector"
430 %typemap(jstype) std::vector<double>, std::vector<double>& "java.util.Vector"
432 // return a Vector of Doubles
433 %typemap(javaout) std::vector<double> {
436 %typemap(out) std::vector<double> {
437 JniWrapper JniWrapper(jenv);
438 $result = JniWrapper.marshalDoubleVector( $1 );
441 /*********************************************************************
443 * Pairs of String (IN/OUT)
445 *********************************************************************/
446 %typemap(jni) std::pair<std::string, std::string>, const std::pair<std::string, std::string>& "jobject"
447 %typemap(jtype) std::pair<std::string, std::string>, const std::pair<std::string, std::string>& "java.util.Vector"
448 %typemap(jstype) std::pair<std::string, std::string>, const std::pair<std::string, std::string>& "java.util.Vector"
449 %typemap(javain) std::pair<std::string, std::string>, const std::pair<std::string, std::string>& "$javainput"
451 // pass in by reference a Vector of std::string
452 %typemap(in) const std::pair<std::string, std::string>& {
453 $1 = new std::pair<std::string, std::string>();
454 JniWrapper JniWrapper(jenv);
455 *($1) = JniWrapper.unmarshalPairString( $input );
459 %typemap(freearg) const std::pair<std::string, std::string>& {
465 // generate:Sample.java
466 // generate:SampleJni.java
467 // generate:SampleTest.java
470 test
.write(['src', 'server', 'JavaSource', 'SConscript'], """\
473 classes=env.Java(target='classes',source=['com'])
475 HelloApplet=os.path.join('#/buildout/HelloApplet/HelloApplet.jar')
476 env['WARXFILES']=['SConscript','.cvsignore']
477 env['WARXDIRS']=['CVS']
478 #env.War('scons',[classes,Dir('../WebContent'),HelloApplet])
481 test
.write(['src', 'server', 'JavaSource', 'com', 'gnu', 'scons', 'web', 'tools', 'Bool.java'], """\
482 package com.gnu.scons.web.tools;
491 public Bool( boolean aFlag )
496 public boolean booleanValue()
503 test
.write(['src', 'server', 'JavaSource', 'com', 'gnu', 'scons', 'web', 'tools', 'StringUtils.java'], """\
504 package com.gnu.scons.web.tools;
506 public class StringUtils
508 public static String toPercent( String value )
510 if ( value.equals("") )
523 test
.write(['src', 'server', 'WebContent', 'index.html'], """\
524 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
527 <META http-equiv="refresh" content="0;URL=go?action=home">
528 <TITLE>index.html</TITLE>
531 <P><a href="go?action=home">go?action=home</a></P>
536 test
.write(['src', 'server', 'WebContent', 'META-INF', 'MANIFEST.MF'], """\
537 Manifest-Version: 1.0
542 test
.write(['src', 'server', 'WebContent', 'WEB-INF', 'web.xml'], """\
543 <?xml version="1.0" encoding="UTF-8"?>
544 <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
545 <web-app id="WebExample">
546 <display-name>scons</display-name>
548 <servlet-name>WebExample</servlet-name>
549 <display-name>WebExample</display-name>
550 <servlet-class>com.gnu.scons.web.tool.WebExample</servlet-class>
553 <servlet-name>WebExample</servlet-name>
554 <url-pattern>/go</url-pattern>
557 <welcome-file>index.html</welcome-file>
558 <welcome-file>index.htm</welcome-file>
563 test
.write(['src', 'server', 'WebContent', 'WEB-INF', 'conf', 'app.properties'], """\
564 logging = webExample.Example
567 test
.write(['src', 'server', 'WebContent', 'theme', 'Master.css'], """\
570 font-family: Helvetica,Sans-Serif;
575 test
.run(arguments
= '.')
577 test
.must_exist(['buildout', 'javah', 'myid.jar'])
578 test
.must_exist(['buildout', 'javah', 'MyID', 'MyID.class'])
580 test
.must_exist(['buildout', 'jni', 'Sample.class'])
581 test
.must_exist(['buildout', 'jni', 'Sample.java'])
582 test
.must_exist(['buildout', 'jni', 'SampleJNI.class'])
583 test
.must_exist(['buildout', 'jni', 'SampleJNI.java'])
584 test
.must_exist(['buildout', 'jni', 'SampleTest.java'])
586 # Some combinations of Java + SWIG apparently don't actually generate
587 # a SampleTest.class file, while others do. Only issue a warning if
589 p
= test
.workpath('buildout', 'jni', 'SampleTest.class')
590 if not os
.path
.exists(p
):
591 print('Warning: %s does not exist' % p
)
593 test
.up_to_date(arguments
= '.')
599 # indent-tabs-mode:nil
601 # vim: set expandtab tabstop=4 shiftwidth=4: