Skip to content

Commit 02a84de

Browse files
committed
Adding support for unit tests on android via NVIDIA nsight tegra.
1 parent 0b84080 commit 02a84de

12 files changed

Lines changed: 264 additions & 25 deletions

File tree

cmake/Toolchain-Android.cmake

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
cmake_minimum_required (VERSION 3.2)
2+
3+
set(CMAKE_SYSTEM_NAME Android)
4+
5+
# Use the clang tool set because it's support for C++11 is superior
6+
set(CMAKE_GENERATOR_TOOLSET DefaultClang)

make.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ def parse_argv():
3838
if value == '-vs2017':
3939
options['compiler'] = 'vs2017'
4040

41+
if value == '-android':
42+
if not platform.system() == 'Windows':
43+
print('Android is only supported on Windows')
44+
sys.exit(1)
45+
46+
options['compiler'] = 'android'
47+
4148
if value == '-clang4':
4249
options['compiler'] = 'clang4'
4350

@@ -93,6 +100,8 @@ def get_generator(compiler, cpu):
93100
return 'Visual Studio 15'
94101
else:
95102
return 'Visual Studio 15 Win64'
103+
elif compiler == 'android':
104+
return 'Visual Studio 14'
96105
elif platform.system() == 'Darwin':
97106
if compiler == 'xcode':
98107
return 'Xcode'
@@ -124,7 +133,7 @@ def set_compiler_env(compiler, options):
124133
print('Unknown compiler: {}'.format(compiler))
125134
sys.exit(1)
126135

127-
def do_generate_solution(cmake_exe, build_dir, options):
136+
def do_generate_solution(cmake_exe, build_dir, cmake_script_dir, options):
128137
compiler = options['compiler']
129138
cpu = options['cpu']
130139
config = options['config']
@@ -136,6 +145,12 @@ def do_generate_solution(cmake_exe, build_dir, options):
136145
if not platform.system() == 'Windows':
137146
extra_switches.append('-DCPU_INSTRUCTION_SET:STRING={}'.format(cpu))
138147

148+
if not platform.system() == 'Windows' and not platform.system() == 'Darwin':
149+
extra_switches.append('-DCMAKE_BUILD_TYPE={}'.format(config.upper()))
150+
151+
if platform.system() == 'Windows' and compiler == 'android':
152+
extra_switches.append('-DCMAKE_TOOLCHAIN_FILE={} --no-warn-unused-cli'.format(os.path.join(cmake_script_dir, 'Toolchain-Android.cmake')))
153+
139154
# Generate IDE solution
140155
print('Generating build files ...')
141156
cmake_cmd = '"{}" .. -DCMAKE_INSTALL_PREFIX="{}" {}'.format(cmake_exe, build_dir, ' '.join(extra_switches))
@@ -146,9 +161,6 @@ def do_generate_solution(cmake_exe, build_dir, options):
146161
print('Using generator: {}'.format(cmake_generator))
147162
cmake_cmd += ' -G "{}"'.format(cmake_generator)
148163

149-
if not platform.system() == 'Windows' and not platform.system() == 'Darwin':
150-
cmake_cmd += ' -DCMAKE_BUILD_TYPE={}'.format(config.upper())
151-
152164
result = subprocess.call(cmake_cmd, shell=True)
153165
if result != 0:
154166
sys.exit(result)
@@ -159,7 +171,10 @@ def do_build(cmake_exe, options):
159171
print('Building ...')
160172
cmake_cmd = '"{}" --build .'.format(cmake_exe)
161173
if platform.system() == 'Windows':
162-
cmake_cmd += ' --config {} --target INSTALL'.format(config)
174+
if options['compiler'] == 'android':
175+
cmake_cmd += ' --config {}'.format(config)
176+
else:
177+
cmake_cmd += ' --config {} --target INSTALL'.format(config)
163178
elif platform.system() == 'Darwin':
164179
cmake_cmd += ' --config {} --target install'.format(config)
165180
else:
@@ -196,6 +211,7 @@ def do_tests(ctest_exe, options):
196211
ctest_exe = os.path.join(cmake_home, 'bin', ctest_exe)
197212

198213
build_dir = os.path.join(os.getcwd(), 'build')
214+
cmake_script_dir = os.path.join(os.getcwd(), 'cmake')
199215

200216
if options['clean'] and os.path.exists(build_dir):
201217
print('Cleaning previous build ...')
@@ -212,7 +228,7 @@ def do_tests(ctest_exe, options):
212228
print('Using compiler: {}'.format(compiler))
213229

214230
if options['build'] or not options['unit_test']:
215-
do_generate_solution(cmake_exe, build_dir, options)
231+
do_generate_solution(cmake_exe, build_dir, cmake_script_dir, options)
216232

217233
if options['build']:
218234
do_build(cmake_exe, options)

tests/CMakeLists.txt

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,8 @@
11
cmake_minimum_required (VERSION 3.2)
2-
project(sjson-cpp_unit_tests)
2+
project(sjson-cpp_unit_tests_root)
33

4-
set(CMAKE_CXX_STANDARD 11)
5-
6-
include_directories("${PROJECT_SOURCE_DIR}/../includes")
7-
include_directories("${PROJECT_SOURCE_DIR}/../external/catch-1.9.6")
8-
9-
# Grab all of our source files
10-
file(GLOB_RECURSE SJSON_CPP_UNIT_TEST_SOURCE_FILES LIST_DIRECTORIES false
11-
${PROJECT_SOURCE_DIR}/sources/*.h
12-
${PROJECT_SOURCE_DIR}/sources/*.cpp)
13-
14-
create_source_groups("${SJSON_CPP_UNIT_TEST_SOURCE_FILES}" ${PROJECT_SOURCE_DIR})
15-
16-
add_executable(sjson-cpp_unit_tests ${SJSON_CPP_UNIT_TEST_SOURCE_FILES})
17-
add_test(NAME UNIT COMMAND sjson-cpp_unit_tests)
18-
19-
setup_default_compiler_flags(${PROJECT_NAME})
20-
21-
install(TARGETS sjson-cpp_unit_tests RUNTIME DESTINATION bin)
4+
if(PLATFORM_ANDROID)
5+
add_subdirectory("${PROJECT_SOURCE_DIR}/main_android")
6+
else()
7+
add_subdirectory("${PROJECT_SOURCE_DIR}/main_generic")
8+
endif()
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
package="com.sjson.cpp"
4+
android:versionCode="1"
5+
android:versionName="1.0">
6+
<uses-sdk android:minSdkVersion="3" />
7+
<application android:label="@string/app_name">
8+
<activity android:name=".MainActivity"
9+
android:label="@string/app_name">
10+
<intent-filter>
11+
<action android:name="android.intent.action.MAIN" />
12+
<category android:name="android.intent.category.LAUNCHER" />
13+
</intent-filter>
14+
</activity>
15+
</application>
16+
</manifest>

tests/main_android/CMakeLists.txt

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
cmake_minimum_required(VERSION 3.2)
2+
project(sjson-cpp_unit_tests)
3+
4+
set(CMAKE_CXX_STANDARD 11)
5+
6+
set(CMAKE_ANDROID_ARCH armv7-a)
7+
set(CMAKE_ANDROID_API_MIN 9)
8+
set(CMAKE_ANDROID_API 15)
9+
set(CMAKE_ANDROID_GUI 1)
10+
11+
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
12+
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
13+
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
14+
15+
set(CMAKE_ANDROID_JAVA_SOURCE_DIR "${PROJECT_SOURCE_DIR}/java")
16+
17+
include_directories("${PROJECT_SOURCE_DIR}/../../includes")
18+
include_directories("${PROJECT_SOURCE_DIR}/../../external/catch-1.9.6")
19+
20+
# Grab all of our test source files
21+
file(GLOB_RECURSE ALL_TEST_SOURCE_FILES LIST_DIRECTORIES false
22+
${PROJECT_SOURCE_DIR}/../sources/*.h
23+
${PROJECT_SOURCE_DIR}/../sources/*.cpp)
24+
25+
create_source_groups("${ALL_TEST_SOURCE_FILES}" ${PROJECT_SOURCE_DIR}/..)
26+
27+
# Grab all of our main source files
28+
file(GLOB_RECURSE ALL_MAIN_SOURCE_FILES LIST_DIRECTORIES false
29+
${PROJECT_SOURCE_DIR}/*.cpp)
30+
31+
create_source_groups("${ALL_MAIN_SOURCE_FILES}" ${PROJECT_SOURCE_DIR})
32+
33+
# Add resource files
34+
set(JAVA_FILES java/com/sjson/cpp/MainActivity.java)
35+
set(RESOURCE_FILES res/values/strings.xml)
36+
set(ANDROID_FILES AndroidManifest.xml)
37+
38+
add_executable(${PROJECT_NAME} ${ALL_TEST_SOURCE_FILES} ${ALL_MAIN_SOURCE_FILES} ${JAVA_FILES} ${RESOURCE_FILES} ${ANDROID_FILES})
39+
40+
target_compile_options(${PROJECT_NAME} PRIVATE -fexceptions)
41+
42+
target_include_directories(${PROJECT_NAME} PUBLIC jni)
43+
44+
target_link_libraries(${PROJECT_NAME} m)
45+
46+
set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 11)
47+
set_target_properties(${PROJECT_NAME} PROPERTIES ANDROID_SKIP_ANT_STEP 0)
48+
set_target_properties(${PROJECT_NAME} PROPERTIES ANDROID_PROGUARD 1)
49+
set_target_properties(${PROJECT_NAME} PROPERTIES ANDROID_PROGUARD_CONFIG_PATH proguard-android.txt)
50+
set_target_properties(${PROJECT_NAME} PROPERTIES ANDROID_SECURE_PROPS_PATH /definitely/insecure)
51+
52+
set_property(TARGET ${PROJECT_NAME} PROPERTY ANDROID_NATIVE_LIB_DIRECTORIES $<TARGET_FILE_DIR:${PROJECT_NAME}>)
53+
set_property(TARGET ${PROJECT_NAME} PROPERTY ANDROID_NATIVE_LIB_DEPENDENCIES ${PROJECT_NAME}.so)

tests/main_android/build.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project name="sjson-cpp_unit_tests" default="help">
3+
<import file="${sdk.dir}/tools/ant/build.xml" />
4+
</project>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.sjson.cpp;
2+
3+
import android.app.Activity;
4+
import android.widget.TextView;
5+
import android.os.Bundle;
6+
7+
public class MainActivity extends Activity {
8+
@Override
9+
public void onCreate(Bundle savedInstanceState) {
10+
super.onCreate(savedInstanceState);
11+
12+
TextView resultTextView = new TextView(this);
13+
14+
System.loadLibrary("sjson-cpp_unit_tests");
15+
16+
int numUnitTestCases = getNumUnitTestCases();
17+
int numFailed = runUnitTests();
18+
19+
if (numFailed == 0)
20+
resultTextView.setText("All " + numUnitTestCases + " test cases ran successfully!");
21+
else
22+
resultTextView.setText(numFailed + " test cases failed!");
23+
24+
setContentView(resultTextView);
25+
}
26+
27+
public native int getNumUnitTestCases();
28+
public native int runUnitTests();
29+
}

tests/main_android/jni/main.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
////////////////////////////////////////////////////////////////////////////////
2+
// The MIT License (MIT)
3+
//
4+
// Copyright (c) 2018 Nicholas Frechette, Cody Jones, and sjson-cpp contributors
5+
//
6+
// Permission is hereby granted, free of charge, to any person obtaining a copy
7+
// of this software and associated documentation files (the "Software"), to deal
8+
// in the Software without restriction, including without limitation the rights
9+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
// copies of the Software, and to permit persons to whom the Software is
11+
// furnished to do so, subject to the following conditions:
12+
//
13+
// The above copyright notice and this permission notice shall be included in all
14+
// copies or substantial portions of the Software.
15+
//
16+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
// SOFTWARE.
23+
////////////////////////////////////////////////////////////////////////////////
24+
25+
#define CATCH_CONFIG_RUNNER
26+
#include <catch.hpp>
27+
28+
#include <jni.h>
29+
30+
extern "C" jint Java_com_sjson_cpp_MainActivity_getNumUnitTestCases(JNIEnv* env, jobject caller)
31+
{
32+
return Catch::getRegistryHub().getTestCaseRegistry().getAllTests().size();
33+
}
34+
35+
extern "C" jint Java_com_sjson_cpp_MainActivity_runUnitTests(JNIEnv* env, jobject caller)
36+
{
37+
char* argv[1] = { nullptr };
38+
int result = Catch::Session().run(0, argv);
39+
40+
return (result < 0xff ? result : 0xff);
41+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# This is a configuration file for ProGuard.
2+
# http://proguard.sourceforge.net/index.html#manual/usage.html
3+
4+
-dontusemixedcaseclassnames
5+
-dontskipnonpubliclibraryclasses
6+
-verbose
7+
8+
# Optimization is turned off by default. Dex does not like code run
9+
# through the ProGuard optimize and preverify steps (and performs some
10+
# of these optimizations on its own).
11+
-dontoptimize
12+
-dontpreverify
13+
# Note that if you want to enable optimization, you cannot just
14+
# include optimization flags in your own project configuration file;
15+
# instead you will need to point to the
16+
# "proguard-android-optimize.txt" file instead of this one from your
17+
# project.properties file.
18+
19+
-keepattributes *Annotation*
20+
-keep public class com.google.vending.licensing.ILicensingService
21+
-keep public class com.android.vending.licensing.ILicensingService
22+
23+
-keepclasseswithmembernames class * {
24+
native <methods>;
25+
}
26+
27+
# keep setters in Views so that animations can still work.
28+
# see http://proguard.sourceforge.net/manual/examples.html#beans
29+
-keepclassmembers public class * extends android.view.View {
30+
void set*(***);
31+
*** get*();
32+
}
33+
34+
# We want to keep methods in Activity that could be used in the XML attribute onClick
35+
-keepclassmembers class * extends android.app.Activity {
36+
public void *(android.view.View);
37+
}
38+
39+
# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
40+
-keepclassmembers enum * {
41+
public static **[] values();
42+
public static ** valueOf(java.lang.String);
43+
}
44+
45+
-keep class * implements android.os.Parcelable {
46+
public static final android.os.Parcelable$Creator *;
47+
}
48+
49+
-keepclassmembers class **.R$* {
50+
public static <fields>;
51+
}
52+
53+
# The support library contains references to newer platform versions.
54+
# Don't warn about those in case this app is linking against an older
55+
# platform version. We know about them, and they are safe.
56+
-dontwarn android.support.**
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<resources>
3+
<string name="app_name">sjson-cpp Unit Tests</string>
4+
</resources>

0 commit comments

Comments
 (0)