diff --git a/java/java.gradle b/java/java.gradle index 62ec77557b..ac48af023e 100644 --- a/java/java.gradle +++ b/java/java.gradle @@ -93,6 +93,27 @@ task jniHeadersNetworkTables { } } +ext.getNativeJNISymbols = { + def symbolsList = [] + + jniHeadersNetworkTables.outputs.files.each { + FileTree tree = fileTree(dir: it) + tree.each { File file -> + file.eachLine { line -> + if (line.trim()) { + if (line.startsWith("JNIEXPORT ") && line.contains('JNICALL')) { + def (p1, p2) = line.split('JNICALL').collect { it.trim() } + // p2 is our JNI call + symbolsList << p2 + } + } + } + } + } + + return symbolsList +} + clean { delete generatedJNIHeaderLoc } diff --git a/ntcore.gradle b/ntcore.gradle index 7449054d91..59ed966aac 100644 --- a/ntcore.gradle +++ b/ntcore.gradle @@ -12,6 +12,7 @@ def ntcoreSetupModel = { project -> if (includeJava) { project.setupJniIncludes(binaries) + project.checkNativeSymbols(project.getNativeJNISymbols) binaries.all { project.setupDef(linker, "${rootDir}/ntcore-jni.def") } diff --git a/toolchains/arm.gradle b/toolchains/arm.gradle index 59173c2aa2..894244c3ad 100644 --- a/toolchains/arm.gradle +++ b/toolchains/arm.gradle @@ -92,3 +92,29 @@ ext.debugStripSetup = { } } } + +ext.checkNativeSymbols = { getSymbolFunc -> + project.tasks.whenObjectAdded { task -> + if (task.name.contains('link') && task.name.contains('SharedLibrary')) { + def library = task.outputFile.absolutePath + task.doLast { + def nmOutput = new ByteArrayOutputStream() + exec { + commandLine "${compilerPrefix}nm", library + standardOutput nmOutput + } + // Remove '\r' so we can check for full string contents + String nmSymbols = nmOutput.toString().replace('\r', '') + + def symbolList = getSymbolFunc() + symbolList.each { + //Add \n so we can check for the exact symbol + def found = nmSymbols.contains(it + '\n') + if (!found) { + throw new GradleException("Found a definition that does not have a matching symbol ${it}") + } + } + } + } + } +} diff --git a/toolchains/linux.gradle b/toolchains/linux.gradle index f2d6b37430..cea85b4b6b 100644 --- a/toolchains/linux.gradle +++ b/toolchains/linux.gradle @@ -59,3 +59,29 @@ ext.debugStripSetup = { } } } + +ext.checkNativeSymbols = { getSymbolFunc -> + project.tasks.whenObjectAdded { task -> + if (task.name.contains('link') && task.name.contains('SharedLibrary')) { + def library = task.outputFile.absolutePath + task.doLast { + def nmOutput = new ByteArrayOutputStream() + exec { + commandLine "nm", library + standardOutput nmOutput + } + // Remove '\r' so we can check for full string contents + String nmSymbols = nmOutput.toString().replace('\r', '') + + def symbolList = getSymbolFunc() + symbolList.each { + //Add \n so we can check for the exact symbol + def found = nmSymbols.contains(it + '\n') + if (!found) { + throw new GradleException("Found a definition that does not have a matching symbol ${it}") + } + } + } + } + } +} diff --git a/toolchains/mac.gradle b/toolchains/mac.gradle index f80a1314fd..902cbb551c 100644 --- a/toolchains/mac.gradle +++ b/toolchains/mac.gradle @@ -46,3 +46,29 @@ ext.debugStripSetup = { } } } + +ext.checkNativeSymbols = { getSymbolFunc -> + project.tasks.whenObjectAdded { task -> + if (task.name.contains('link') && task.name.contains('SharedLibrary')) { + def library = task.outputFile.absolutePath + task.doLast { + def nmOutput = new ByteArrayOutputStream() + exec { + commandLine "nm", library + standardOutput nmOutput + } + // Remove '\r' so we can check for full string contents + String nmSymbols = nmOutput.toString().replace('\r', '') + + def symbolList = getSymbolFunc() + symbolList.each { + //Add \n so we can check for the exact symbol + def found = nmSymbols.contains(it + '\n') + if (!found) { + throw new GradleException("Found a definition that does not have a matching symbol ${it}") + } + } + } + } + } +} diff --git a/toolchains/windows.gradle b/toolchains/windows.gradle index e093962709..54a039ba26 100644 --- a/toolchains/windows.gradle +++ b/toolchains/windows.gradle @@ -50,3 +50,7 @@ ext.setupDef = { linker, deffile -> // This is a noop on Windows. On gcc platforms, we strip the release binary and create a separate // debug library, but Windows already separates debug symbols into a .pdb file. ext.debugStripSetup = { } + +// This is a noop on Windows. The def file already implicilty checks for the symbols +ext.checkNativeSymbols = { getSymbolFunc -> +}