Some C functions require __ANDROID_API__ to be set.
For example, the following will not compile without 'implicit declaration' errors on Nougat+:
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
int main(void) {
const char *hello_world = "Hello, world!";
char *world = strchrnul(hello_world, 'w');
if (world)
puts(world);
return 0;
}
```
$ clang test.c
test.c:7:16: warning: implicit declaration of function 'strchrnul' is invalid in C99 [-Wimplicit-function-declaration]
char *world = strchrnul(hello_world, 'w');
^
test.c:7:8: warning: incompatible integer to pointer conversion initializing
'char *' with an expression of type 'int' [-Wint-conversion]
char *world = strchrnul(hello_world, 'w');
^ ~~~~~~~
2 warnings generated.
Compile with `__ANDROID_API__` defined to 24 or higher (assuming, again, that you are running Nougat or above), and it works fine.
Clang does have a config file that can do that, but in order for the file to be loaded, you would have to set the CMake flag `-DCLANG_CONFIG_FILE_SYSTEM_DIR` while compiling Clang to a valid path, then it will automatically load the config file.
After that, all you would need to do is add a shell script to the postinstall script that does something like this:
```sh
#!/data/data/com.termux/files/usr/bin/dash
API_STR="-D__ANDROID_API__="
API_LEVEL="$(getprop ro.build.version.sdk)"
CONFIG_FILE="<config file path>"
echo "Updating Clang's config file..."
# Check if the file exists and it contains "-D__ANDROID_API__="
if [ -f "${CONFIG_FILE}" ] && [ "$(busybox grep -qs "${API_STR}" "${CONFIG_FILE}")" ]
then
# Check if this config file is from an older Android version, if so, update it
if [ ! "$(busybox grep -qs "${API_STR}${API_LEVEL}" "${CONFIG_FILE}")" ]
then
busybox sed -i'' -e "s#${API_STR}[0-9]\*#${API_STR}${API_LEVEL}#g" "${CONFIG_FILE}"
fi
# Otherwise, do nothing as the file has the latest version
else
# We now can just append __ANDROID_API__ to the file.
echo "${API_STR}${API_LEVEL}" >> "${CONFIG_FILE}"
fi
Make sure it gets tested, I just wrote this blindly. I am not the greatest at shell scripts or sed, and I don't know much about dpkg either.
If this works properly, Clang should automatically define __ANDROID_API__, and that source file should compile without issues, again, assuming you are running Nougat or later.
In Termux the file <android/api-level.h> (which gets included from <sys/cdefs.h>, which in turn is included in almost all libc include files) contains:
#ifndef __ANDROID_API__
#define __ANDROID_API__ 21
So __ANDROID_API__ already gets defined if not passed explicitly - but to a default value of 21, which is currently the minimum supported api level of Termux (soon to be bumped to 23).
I guess you expect this to be set to the api level of the currently running device, which I guess is not unreasonable?
Yes.
I think the current situation is actually buggy: android/api-level.h defines __ANDROID_API__ to a different value from the libc that is used by default.
This causes problems when for example trying to build code that tests (e.g. with autoconf) for functions in libc. These can pass (e.g. on my Oreo phone, the test for mempcpy passes), but then compilation is incorrect, because mempcpy requires __ANDROID_API__ to be at least 23. In fact this only causes a warning (for undeclared function), but the resulting code crashes.
So whatever solution is chosen (whether to set an arbitrary minimum API level, or to set the maximum supported by the device), the __ANDROID_API__ value should match the default libc.
So
__ANDROID_API__already gets defined if not passed explicitly - but to a default value of 21, which is currently the minimum supported api level of Termux (soon to be bumped to 23).
@fornwall I humbly ask you, and would even beg you, to _please_ keep compatibility with API level 21, there are many of us, especially in third world countries, who can't afford to buy a new device in order to get to the new api level.
I'd really love to have this feature. As @easyaspi314 said, the compilation often fails due to "implicit declaration", especially when a configure script is used.
Typically, ./configure checks if a function is "linkable" or not. However, the compilation requires a prototype declaration for the function, which is sometimes disabled when __ANDROID_API__ is lower.
For example, my Android 9 Pie (API version 28) provides a function pthread_attr_setinheritsched. When running the configure script on Termux, the function is actually linkable, so it defines a macro namely HAVE_PTHREAD_ATTR_SETINHERITSCHED. However, pthread.h declares the function only when __ANDROID_API__ >= 28:
#if __ANDROID_API__ >= 28
int pthread_attr_setinheritsched(pthread_attr_t* __attr, int __flag) __INTRODUCED_IN(28);
#endif /* __ANDROID_API__ >= 28 */
Currently, it is not declared by default because __ANDROID_API__ is 21. So, the following code leads to an "implicit declaration" error. (Decent projects tend to use -Werror=implicit-function-declaration.)
#ifdef HAVE_PTHREAD_ATTR_SETINHERITSCHED
pthread_attr_setinheritsched(...);
#endif
I think that @erlanger's concern about the API version is less relevant in this particular case. I believe that almost all Termux users just want to build a program only for themselves. Few people will distribute a binary compiled on Termux. If they want to do so seriously, they should use a cross-compiler and create a portable package, I think.
Currently, it is not declared by default because __ANDROID_API__ is 21
We have split repositories for legacy (Android 5/6) and Android 7+ devices.
Android 7 repo has API 24.
https://wiki.termux.com/wiki/New_package_repository
Anyway I agree that we should set __ANDROID_API__ to which device have. The only problem is best/reliable way to determine current API from clang.
For now I think we can just export env variable like TERMUX_ANDROID_API_LEVEL and attempt to read it from clang but it obviously may be unset somehow (e.g. via build script or whatever else).
Most helpful comment
@fornwall I humbly ask you, and would even beg you, to _please_ keep compatibility with API level 21, there are many of us, especially in third world countries, who can't afford to buy a new device in order to get to the new api level.