Proguard: How to keep everything except specific condition? - proguard

I'm using Proguard to obfuscate my code, and I need to keep every third party libraries like:
-keep class com.layer.**
-dontwarn com.layer.**
-keep class com.twitter.**
-keep class android.support.**
-keep class com.crashlytics.** { *; }
-dontwarn com.crashlytics.**
...
And whenever I add a new third party library, I need to check its package name and add it to my proguard config file, or the app may crashes.
Can't I write the rule just like this? I don't care about codes that's not mine.
-keep class !(my.package.name.**)
-dontwarn !(my.package.name.**)
Thanks!

To keep everything except classes in your own package you can use the rule that you already pointed out (excluding the brackets):
-keep class !my.package.name.** { *; }
This will implicitly keep everything else.
You still can add additionally -keep rules for your classes if needed.
The rule for the -dontwarn should work in a similar way:
-dontwarn !my.package.name.**,**
You can also add similar -dontnote rules if needed.

Related

gradlew assemble error: can't find referenced class java.lang.invoke.LambdaMetafactory

I'm experiencing a strange error that only happens when I try to build my project using the gradlew script file.
If I run gradlew assemble Proguard it's complaining in multiple classes (in the same module) with the following warning:
can't find referenced class java.lang.invoke.LambdaMetafactory
Of course I have the following rule inside my module and main project proguard-rules.pro file:
-dontwarn java.lang.invoke.**
-dontwarn **$$Lambda$*
But even with that Proguard it's still complaining about the same warning...
Now the strange part is, if I run a different job, for example assembleRelease, assembleDebug, or assembleQA (A custom job that I make) the process finish without any problem...
I'm getting out of ideas here...

Unable to ignore proguard warning

I'm trying to add Detox e2e testing to my project, and when I run the assembleAndroidTest I get proguard warnings that fails the build:
Warning: library class android.content.Intent depends on program class org.xmlpull.v1.XmlPullParser
Warning: library class android.content.IntentFilter depends on program class org.xmlpull.v1.XmlSerializer
Warning: library class android.content.IntentFilter depends on program class org.xmlpull.v1.XmlPullParser
Warning: library class android.graphics.drawable.BitmapDrawable depends on program class org.xmlpull.v1.XmlPullParser
Warning: library class android.graphics.drawable.Drawable depends on program class org.xmlpull.v1.XmlPullParser
Warning: library class android.graphics.drawable.Drawable depends on program class org.xmlpull.v1.XmlPullParser
Warning: library class android.graphics.drawable.Drawable depends on program class org.xmlpull.v1.XmlPullParser
Warning: library class android.graphics.drawable.Drawable depends on program class org.xmlpull.v1.XmlPullParser
Warning: library class android.graphics.drawable.Drawable depends on program class org.xmlpull.v1.XmlPullParser
Warning: library class android.graphics.drawable.Drawable depends on program class org.xmlpull.v1.XmlPullParser
Warning: library class android.util.Xml depends on program class org.xmlpull.v1.XmlPullParser
Warning: library class android.util.Xml depends on program class org.xmlpull.v1.XmlSerializer
Warning: library class android.util.Xml depends on program class org.xmlpull.v1.XmlPullParser
Note: there were 13 unresolved dynamic references to classes or interfaces.
You should check if you need to specify additional program jars.
(http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclass)
Note: there were 39 accesses to class members by means of introspection.
You should consider explicitly keeping the mentioned class members
(using '-keep' or '-keepclassmembers').
(http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclassmember)
Warning: there were 89 unresolved references to classes or interfaces.
You may need to add missing library jars or update their versions.
If your code works fine without the missing classes, you can suppress
the warnings with '-dontwarn' options.
(http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedclass)
Warning: there were 16 instances of library classes depending on program classes.
You must avoid such dependencies, since the program classes will
be processed, while the library classes will remain unchanged.
(http://proguard.sourceforge.net/manual/troubleshooting.html#dependency)
Couldn't find any dontwarn that suppressed it and allowed me to build the project, This SO thread didn't worked either.
Thanks

How to remove compile dependencies for cmake static libraries?

Consider this CMake setup:
add_library( A STATIC modules/a/src/src1.cpp modules/a/src/src2.cpp )
target_include_directories( A PUBLIC modules/a/inc )
target_compile_definitions( A PUBLIC USING_A=1 )
add_library( B STATIC modules/b/src/src1.cpp modules/b/src/src2.cpp )
target_include_directories( B PUBLIC modules/b/inc )
target_compile_definitions( B PUBLIC USING_B_WRAPPER=1 )
target_link_libraries( B PUBLIC A )
add_library( C STATIC modules/c/src/src1.cpp )
target_include_directories( C PUBLIC modules/c/inc )
target_link_libraries( C PUBLIC B )
Let's assume that headers from modules/b/inc include headers from modules/a/inc, so any consumer of B library must also add modules/a/inc to its includes path and also add USING_A=1 preprocessor definition.
Let's use the Ninja Generator (however the problem occurs with any generator, including Makefile, Xcode and Visual Studio):
cmake -GNinja ../path/to/source
And let's build the C library:
ninja libC.a
Everything builds correctly, however lots of time gets wasted into building libA.a and libB.a just to build the libC.a.
If I change the C's dependency on B to INTERFACE, then libA.a and libB.a are not built, but compilation of modules/c/src/src1.cpp fails because include directories and compile definitions that should be inherited from B and its dependencies are not inherited.
Is there a way to tell CMake that specific target should not compile-depend on specific target specified in target_link_libraries list (link-dependency should remain)? I am aware that sometimes those dependencies are required (such as if, for example, A depended on some custom command generating headers for it dependees), but this is not the case here. I am searching for a solution to specify for each static library target whether or not it should compile-depend on another static library target, while still keeping the link dependency and obtaining all correct compile flags from its dependencies.
Currently I know no way for issue target_link_libraries without complete target-level dependencies. And not sure that things will change in a near future. CMake developer's post from the bugreport:
Using target_link_libraries has always been enough to get an ordering dependency and many projects depend on this. We cannot change that for any target type.
What can be done without changing semantics is for the Ninja generator to detect when the transitive closure of a dependency doesn't have any custom commands and in that case drop ordering dependencies on it from the compilation rules and custom commands. Only the full dependency of the link step on the dependency's library file is needed. Work on this would be better discussed on the developer mailing list.
That answer on related question suggests to refuse from target_link_libraries between STATIC libraries, which removes some unneded dependencies. I have adapted that scenario for your purpose:
Non-natural way
Express "compile-time dependencies" with INTERFACE libraries. Real libraries will be used only for link an executable or a SHARED library.
# Compile-time dependency.
add_library( A_compile INTERFACE )
target_include_directories( A_compile PUBLIC modules/a/inc )
target_compile_definitions( A_compile PUBLIC USING_A=1 )
# Real library.
add_library( A STATIC modules/a/src/src1.cpp modules/a/src/src2.cpp )
target_link_libraries(A A_compile)
# Compile-time dependency.
add_library( B_compile INTERFACE )
target_include_directories( B_compile PUBLIC modules/b/inc )
target_compile_definitions( B_compile PUBLIC USING_B_WRAPPER=1 )
target_link_libraries( B_compile PUBLIC A_compile )
# Real library
add_library( B STATIC modules/b/src/src1.cpp modules/b/src/src2.cpp )
target_link_libraries(B B_compile)
# Final STATIC library.
add_library( C STATIC modules/c/src/src1.cpp )
target_include_directories( C PUBLIC modules/c/inc )
target_link_libraries( C PUBLIC B_compile )
# ...
# Creation executable or non-STATIC library, linked with C
add_executable(my_exe ...)
# Need to manually list libraries, "compile-time linked" to C.
target_link_libraries(my_exe C B A)
Becase for executable or non-STATIC library target_link_libraries uses real STATIC libraries, these STATIC libraries will be built before even object files for such executable/SHARED library.
We've been using the following function to link static libraries against one another without causing build order dependencies between them for several years now. While not perfect, we've been quite happy with it overall.
function(target_link_static_libraries target)
if(BUILD_STATIC_LIBS_IN_PARALLEL)
target_link_libraries(${target} INTERFACE ${ARGN})
foreach(lib ${ARGN})
target_include_directories(${target} PUBLIC $<TARGET_PROPERTY:${lib},INTERFACE_INCLUDE_DIRECTORIES>)
target_include_directories(${target} SYSTEM PUBLIC $<TARGET_PROPERTY:${lib},INTERFACE_SYSTEM_INCLUDE_DIRECTORIES>)
target_compile_definitions(${target} PUBLIC $<TARGET_PROPERTY:${lib},INTERFACE_COMPILE_DEFINITIONS>)
target_compile_options(${target} PUBLIC $<TARGET_PROPERTY:${lib},INTERFACE_COMPILE_OPTIONS>)
endforeach()
else()
target_link_libraries(${target} PUBLIC ${ARGN})
endif()
endfunction()
Known drawbacks:
Boolean transitive properties like PIC don't get automatically get applied.
The dependencies aren't shown when generating dependency graphs.
When an error occurs finding a dependency, it often spits out hundreds of lines of error messages, since we essentially defer the checking for the existence of libraries until it has been propagated out to dozens of targets.
Improvements or fixes for any of the above would be very much appreciated.

Inherit include directories from used library in CMake

If I have a library with public header files which are used by another library's public header files how can I expose the former library's public header directory to a third application which depends only from the latter library without explicitly adding the former library's header files' path to the application's target_include_directories section?
I know this is a bit confusing, here is a simple example:
I have two shared libraries and one application in the same cmake project:
library_foo has a directory which contains its public header files
library_bar has also a directory with its public header files. One of these public header files (lib_bar/bar.h) contains an #include <lib_foo/foo.h> entry, i.e. the public header file has a reference to a public header file defined in library_foo.
library_bar implementation depends on library_foo.
app depends directly only on the library_bar.
app's main.cpp contains an #include <lib_bar/bar.h>.
So, app depends indirectly from library_foo and its header files as well.
I would like to write three CMakeLists.txt files for these three parts of my application. In the CMakeLists.txt of app I would like to specify dependency only to library_bar, i.e. the library and header dependecies from libarary_foo which are specified in library_bar CMakeLists.txt must be transferred to app. How can I do this? I would like to use target_* solution.
Command target_include_directories is used exactly for the purpose of inheritance:
add_library(library_foo SHARED ...)
# Include directories are made an interface of 'foo'.
target_include_directories(library_foo PUBLIC <dir-with-lib_foo/foo.h>)
add_library(library_bar SHARED ...)
target_include_directories(library_bar PUBLIC <dir-with-lib_bar/bar.h>)
# Linking with 'foo' propagates include directories
# and makes these directories an interface of 'bar' too.
target_link_libraries(library_bar library_foo)
add_executable(app ...)
# Application will use include directories both from 'bar' and 'foo'.
target_link_libraries(app library_bar)

What are the differences between IMPORTED target and INTERFACE libraries?

As I understand it INTERFACE libraries are like Visual Studio property sheets, so very useful. We can use it to link with static libs and propagate properties.
But IMPORTED targets bother me : I can't see a problem which can be solved with IMPORTED target only.
When you create an imported target, you're telling CMake: I have this { static library | shared library | module library | executable } already built in this location on disk. I want to be able to treat it just like a target built by my own buildsystem, so take note that when I say ImportedTargetName, it should refer to that binary on disk (with the associated import lib if applicable, and so on).
When you create an interface library, you're telling CMake: I have this set of properties (include directories etc.) which clients can use, so if they "link" to my interface library, please propagate these properties to them.
The fundamental difference is that interface libraries are not backed by anything on disk, they're just a set of requirements/properties. You can set the INTERFACE_LINK_LIBRARIES property on an interface library if you really want to, but that's not really what they were designed for. They're to encapsulate client-consumable properties, and make sense primarily for things like header-only libraries in C++.
Also notice that an interface library is a library—there's no such thing as an interface executable, but you can indeed have imported executables. E.g. a package config file for Bison could define an imported target for the Bison executable, and your project could then use it for custom commands:
# In Bison package config file:
add_executable(Bison IMPORTED)
set_property(TARGET Bison PROPERTY IMPORTED_LOCATION ...)
# In your project:
find_package(Bison)
add_custom_command(
OUTPUT parser.c
COMMAND Bison tab.y -o parser.c
DEPENDS tab.y
...
)
(Bison is used just as an example of something you might want to use in custom commands, and the command line is probably not right for it).
It seems like there is a lot of overlap. Say you have a shared library and headers on disk and you want to make it available so that bits of your CMake can do this
target_link_libraries(my_target foo)
and automatically link with it and get the necessary include directories.
You can do it either like this:
find_package(Foo)
add_library(foo SHARED IMPORTED)
set_target_properties(foo PROPERTIES
IMPORTED_LOCATION ${FOO_LIBRARIES} # The DLL, .so or .dylib
INTERFACE_INCLUDE_DIRECTORIES ${FOO_INCLUDE_DIR}
INTERFACE_COMPILE_DEFINITIONS "ENABLE_FOO"
)
Or like this:
add_library(foo INTERFACE)
target_link_libraries(foo INTERFACE ${FOO_LIBRARIES})
target_include_directories(foo INTERFACE ${FOO_INCLUDE_DIR})
target_compile_definitions(foo INTERFACE "-DENABLE_FOO")
They both work and behave identically as far as I can tell. There is even an 'imported interface library' available via add_library(foo INTERFACE IMPORTED) though that didn't seem to work and I have no idea what it is for.
Frankly the docs don't really explain which you should use for libraries, and I'm afraid I don't find Angew's "that's not really what they were designed for" very compelling.
I guess use either. I think the interface library is easier to understand and more consistent with the use of INTERFACE properties from internal libraries.