How to add conditional code in Android.bp - build

AOSP now has new build system, and file Android.bp has replaced Android.mk in many places.
Now I want to list source files conditionally depending on platform.
Say something like this:
if(atom)
{
src: [
.......list of files.......
],
exclude_srcs: [
.......list of files.......
]
} else
{
src: [
.......list of files.......
],
exclude_srcs: [
.......list of files.......
]
}
Any suggestions how to achieve this?
Also, how can I achieve logical operations like NOT, OR etc in conditionals?
Thanks in advance.

Quote from documentation:
By design, Android.bp files are very simple. There are no conditionals or control flow statements - any complexity is handled in build logic written in Go.
You can read it here.

GO
You can write a go script with your conditions. Follow
Is there a way to add/remove module in Android.bp?
What is art.go? And why is it considered a way to write conditionals in bp files?
Conditional compilation
If you just want to include a module conditionally you can define many Android.bp modules and include them based on conditions in Android.mk files.
https://android.googlesource.com/platform/build/soong/+/HEAD/docs/best_practices.md#removing-conditionals
soong_config_modules
You will face parsing errors if any of your Android.bp files include libraries not supported by your AOSP.
To fix that you can use soong_config_modules. Note that this is supported only Android 11 R onwards.
Details are given in https://android.googlesource.com/platform/build/soong/+/refs/heads/master/android/soong_config_modules.go
However, I'll give you an example.
Here I am including special libraries when the AOSP is Android 12. Since these libraries might not be present on lower versions, I will not include iot-camera-system.mk in PRODUCT_PACKAGES so it will not be included as a preinstalled app.
What specifically I will achieve with soong_config_modules is removal of parsing errors when these libraries are not present (Android parses all Android.bp files to form a parse tree, it also checks for the existence of their dependencies and build fails when they are not present).
iot-camera-system.mk
# CameraApp Android Application Package
ifeq ($(PLATFORM_VERSION), $(filter $(PLATFORM_VERSION),S 12))
PRODUCT_PACKAGES += CameraApp
SOONG_CONFIG_NAMESPACES += camera
SOONG_CONFIG_camera += camtargets
SOONG_CONFIG_camera_camtargets := newCameraTarget
else
SOONG_CONFIG_NAMESPACES += camera
SOONG_CONFIG_camera += camtargets
SOONG_CONFIG_camera_camtargets := oldCameraTarget
endif
Android.bp
// This introduces the module type camera_cc_defaults
// If target.mk file contained:
//
// SOONG_CONFIG_NAMESPACES += camera
// SOONG_CONFIG_camera += camtargets
// SOONG_CONFIG_camera_camtargets := newCameraTarget
//
// Then our libs would build with static_libs
soong_config_module_type {
name: "camera_cc_defaults",
module_type: "cc_defaults",
config_namespace: "camera",
variables: ["camtargets"],
properties: ["static_libs"],
}
soong_config_string_variable {
name: "camtargets",
values: ["oldCameraTarget", "newCameraTarget"],
}
camera_cc_defaults {
name: "camera_defaults",
soong_config_variables: {
camtargets: {
oldCameraTarget: {
static_libs: [
],
},
newCameraTarget: {
static_libs: [
"androidx.core_core-ktx",
"androidx.fragment_fragment-ktx",
"androidx.navigation_navigation-fragment-ktx",
"androidx.navigation_navigation-ui-ktx",
"androidx.lifecycle_lifecycle-runtime-ktx",
"kotlinx_coroutines",
"kotlinx_coroutines_android",
],
},
},
},
}
android_library {
name: "utils",
defaults: ["camera_defaults"],
manifest: "utils/src/main/AndroidManifest.xml",
platform_apis: true,
srcs: [
"utils/src/main/java/com/example/android/camera/utils/*.kt",
],
resource_dirs: [
"utils/src/main/res/",
],
static_libs: [
"androidx-constraintlayout_constraintlayout",
"androidx.appcompat_appcompat",
"androidx.localbroadcastmanager_localbroadcastmanager",
"com.google.android.material_material",
"androidx.exifinterface_exifinterface",
"androidx.core_core",
"androidx.preference_preference",
"androidx.fragment_fragment",
"androidx.recyclerview_recyclerview",
"androidx.lifecycle_lifecycle-runtime",
"androidx.lifecycle_lifecycle-extensions",
"kotlin-stdlib",
"kotlin-reflect",
"gson-prebuilt-jar",
],
optimize: {
enabled: false,
},
dex_preopt: {
enabled: false,
},
}
android_app {
name: "CameraApp",
defaults: ["camera_defaults"],
manifest: "app/src/main/AndroidManifest.xml",
privileged: true,
platform_apis: true,
certificate: "platform",
srcs: [
"app/src/main/java/com/example/android/camera2/video/*.kt",
"app/src/main/java/com/example/android/camera2/video/fragments/*.kt",
"app/src/main/java/com/example/android/camera2/video/overlay/*.kt",
],
resource_dirs: [
"app/src/main/res/",
],
static_libs: [
"androidx-constraintlayout_constraintlayout",
"androidx.appcompat_appcompat",
"androidx.localbroadcastmanager_localbroadcastmanager",
"com.google.android.material_material",
"androidx.exifinterface_exifinterface",
"androidx.core_core",
"androidx.preference_preference",
"androidx.fragment_fragment",
"androidx.recyclerview_recyclerview",
"androidx.lifecycle_lifecycle-runtime",
"androidx.lifecycle_lifecycle-extensions",
"kotlin-stdlib",
"kotlin-reflect",
"gson-prebuilt-jar",
"utils",
],
optimize: {
enabled: false,
},
dex_preopt: {
enabled: false,
},
}

this a sample on how to add a conditional in a bp file:
cc_library {
...
srcs: ["generic.cpp"],
arch: {
arm: {
srcs: ["arm.cpp"],
},
x86: {
srcs: ["x86.cpp"],
},
},
}

Related

React Native Expo App: How to get it to run Jest tests

So Jest seems to be broken out of the box right now, when creating a React Native App with Expo.
Steps to reproduce:
`expo init'
Choose tabs.
cd into your app.
Run npm test 👉🏻 Fails
I googled and tried out the following fixes:
A) Add jest.config.js:
module.exports = {
preset: 'jest-expo',
transform: {
'\\.js$': '<rootDir>/node_modules/react-native/jest/preprocessor.js',
}
};
B) Copy react-natives preprocessor in your own `jest.preprcessor.js' file:
transform: {
/*
* Stop jest from falling over on its face.
* cf. https://github.com/expo/expo/issues/2595#issuecomment-440966998
* cf. https://github.com/facebook/react-native/issues/22175#issuecomment-436959462
*/
'\\.js$': '<rootDir>/jest.preprocessor.js',
},
C) Changing the "test" scripts section
from:
"test": "node_modules/.bin/jest"
to:
"test": "node ./node_modules/jest/bin/jest.js"
So nothing works 😓 All approaches result in some or all tests failing.
Does anyone know how to get jest to work with Expo 32?
Edit: Bruno's answer works. Additionally, make sure to delete your node_modules and package-lock.json before running yarn. Furthermore, you don't need a jest.config.js. And you also don't need Bruno's babel.config.js. Here is mine:
module.exports = function(api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
};
};
It's so weird that it doesn't work for npm.
PS, here is the preprocessor code so you don't have to search it:
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* #format
* #flow
*/
/* eslint-env node */
'use strict';
const {transformSync: babelTransformSync} = require('#babel/core');
/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
* found when Flow v0.54 was deployed. To see the error delete this comment and
* run Flow. */
const babelRegisterOnly = require('metro-babel-register');
/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
* found when Flow v0.54 was deployed. To see the error delete this comment and
* run Flow. */
const createCacheKeyFunction = require('fbjs-scripts/jest/createCacheKeyFunction');
const generate = require('#babel/generator').default;
const nodeFiles = RegExp(
[
'/local-cli/',
'/metro(?:-[^/]*)?/', // metro, metro-core, metro-source-map, metro-etc
].join('|'),
);
const nodeOptions = babelRegisterOnly.config([nodeFiles]);
babelRegisterOnly([]);
/* $FlowFixMe(site=react_native_oss) */
const transformer = require('metro/src/reactNativeTransformer');
module.exports = {
process(src /*: string */, file /*: string */) {
if (nodeFiles.test(file)) {
// node specific transforms only
return babelTransformSync(src, {
filename: file,
sourceType: 'script',
...nodeOptions,
ast: false,
}).code;
}
const {ast} = transformer.transform({
filename: file,
localPath: file,
options: {
ast: true, // needed for open source (?) https://github.com/facebook/react-native/commit/f8d6b97140cffe8d18b2558f94570c8d1b410d5c#r28647044
dev: true,
inlineRequires: true,
minify: false,
platform: '',
projectRoot: '',
retainLines: true,
sourceType: 'unambiguous', // b7 required. detects module vs script mode
},
src,
plugins: [
[require('#babel/plugin-transform-block-scoping')],
// the flow strip types plugin must go BEFORE class properties!
// there'll be a test case that fails if you don't.
[require('#babel/plugin-transform-flow-strip-types')],
[
require('#babel/plugin-proposal-class-properties'),
// use `this.foo = bar` instead of `this.defineProperty('foo', ...)`
{loose: true},
],
[require('#babel/plugin-transform-computed-properties')],
[require('#babel/plugin-transform-destructuring')],
[require('#babel/plugin-transform-function-name')],
[require('#babel/plugin-transform-literals')],
[require('#babel/plugin-transform-parameters')],
[require('#babel/plugin-transform-shorthand-properties')],
[require('#babel/plugin-transform-react-jsx')],
[require('#babel/plugin-transform-regenerator')],
[require('#babel/plugin-transform-sticky-regex')],
[require('#babel/plugin-transform-unicode-regex')],
[
require('#babel/plugin-transform-modules-commonjs'),
{strict: false, allowTopLevelThis: true},
],
[require('#babel/plugin-transform-classes')],
[require('#babel/plugin-transform-arrow-functions')],
[require('#babel/plugin-transform-spread')],
[require('#babel/plugin-proposal-object-rest-spread')],
[
require('#babel/plugin-transform-template-literals'),
{loose: true}, // dont 'a'.concat('b'), just use 'a'+'b'
],
[require('#babel/plugin-transform-exponentiation-operator')],
[require('#babel/plugin-transform-object-assign')],
[require('#babel/plugin-transform-for-of'), {loose: true}],
[require('#babel/plugin-transform-react-display-name')],
[require('#babel/plugin-transform-react-jsx-source')],
],
});
return generate(
ast,
{
code: true,
comments: false,
compact: false,
filename: file,
retainLines: true,
sourceFileName: file,
sourceMaps: true,
},
src,
).code;
},
getCacheKey: createCacheKeyFunction([
__filename,
require.resolve('metro/src/reactNativeTransformer'),
require.resolve('#babel/core/package.json'),
]),
};
My dependencies:
"dependencies": {
"#expo/samples": "2.1.1",
"expo": "^32.0.0",
"formik": "^1.5.0",
"i18n-js": "^3.2.1",
"prop-types": "^15.7.1",
"react": "16.5.0",
"react-native": "https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz",
"react-navigation": "^3.0.9",
"yup": "^0.26.10"
},
"devDependencies": {
"babel-eslint": "^10.0.1",
"babel-preset-expo": "^5.0.0",
"eslint": "^5.13.0",
"eslint-plugin-import": "^2.16.0",
"eslint-plugin-jsx-a11y": "^6.2.1",
"eslint-plugin-react": "^7.12.4",
"eslint-plugin-react-native": "^3.6.0",
"eslint-plugin-react-native-a11y": "^1.2.0",
"eslint-plugin-simple-import-sort": "^3.0.0",
"jest-expo": "^32.0.0",
"react-native-elements": "^1.0.0",
"react-native-testing-library": "^1.5.0"
},
Your dependecies and devDependencies seem fine.
First thing, install yarn. Follow this link for instructions.
Second, you must alter a few things in your package.json. Like this:
"scripts": {
"test": "jest",
...
},
"jest": {
"preset": "jest-expo",
"transform": {
"^.+\\.js$": "babel-jest"
},
}
Third, ensure your babel.config.js is setup correctly. Here's the one from my project running Expo's SDK 32:
module.exports = function (api) {
api.cache(true);
return {
presets: [
'babel-preset-expo',
'module:react-native-dotenv',
],
sourceMaps: true,
plugins: [
'#babel/transform-react-jsx-source',
],
};
};
Lastly, use yarn to install your packages yarn install and to run your tests yarn test.

Can i use my own plugin or extend in stylelint engine with CodeClimate

In my stylelintrc.js
module.exports = {
"extends": [
"stylelint-config-standard",
"stylelint-config-css-modules",
],
"plugins": [
"stylelint-performance-animation",
],
...
In codeclimat.yaml i turn on stylelint engine and take this error on codeclimete
•• Timing: .engineConfig: 0.049s
Error: Could not find "stylelint-config-css-modules". Do you need a configBasedir?
See our documentation at https://docs.codeclimate.com/docs/stylelint for more information.
Can somebody explain me how enable plugins ands extends if it posible?
This is an answer for anyone coming here from google:
Weirdly enough stylelint needs to be given the absolue path of the node_modules folder. Below is a working solution:
const { resolve } = require('path')
const basePath = resolve(__dirname, 'node_modules')
const groupSelectors = `${basePath}/stylelint-group-selectors`
const cssTreeValidator = `${basePath}/stylelint-csstree-validator`
module.exports = {
plugins: [groupSelectors, cssTreeValidator],
extends: [
'stylelint-config-recommended-scss',
'stylelint-config-recess-order',
'stylelint-prettier/recommended',
'stylelint-scss',
'stylelint-a11y/recommended',
],
rules: {
'no-empty-source': null,
//check and add avaialble rules here: https://github.com/kristerkari/stylelint-scss
'scss/selector-no-redundant-nesting-selector': true,
'plugin/stylelint-group-selectors': true,
'csstree/validator': true,
},
}

GYP default value for variable %

i'm trying to play around with GYP and got stucked with defining "default variable"
have 2 files(one main, and one expected to store common data, included to main:
1) v_common.gypi:
{
'variables': {
'mymodule%': "blblblb",
'mymoduleLibs' : "<(mymodule)/Libs",
},
'target_defaults': {
},
}
2) mymodule.gyp
{
'variables':{
},
'includes': [
'v_common.gypi',
], # includes
'targets': [
{
'target_name': 'myModule',
'type': 'none',
'actions' : [
{
'action_name': 'create_libs_folder',
'inputs': ['one_file'],
'outputs':['blabla'],
'action': ['mkdir', '<(mymoduleLibs)'],
}
]
},
], # targets
}
per my expectations:
mymodule should get value of "blblblb", (as far as it wasn't defined previously anywhere),
then I should be able to use it for compute value of mymoduleLibs
and after all mymoduleLibs should be usable in mymodule.gyp
but, i just getting error that mymodule is "Undefined variable". If I do exact definition of mymodyle like in example below(withot percent sign), everything works fine. :
'variables': {
'mymodule': "blblblb",
'mymoduleLibs' : "<(mymodule)/Libs",
}
any ideas?
i've found issue. it's described here https://groups.google.com/forum/?fromgroups#!topicsearchin/gyp-developer/default/gyp-developer/1EWXAXe-qWs
correct workaroud is to define default variables in sub-dict 'variables':{...}, so they will be evaluated before expanding other variables, like below:
{
'variables': {
'variables': {
'mymodule%': "blblblb",
},
'mymoduleLibs' : "<(mymodule)/Libs",
},
'target_defaults': {
},
}

How to use QtWebkit with geolocation?

It is possible to use geolocation in Desktop applications with QWebView?
I tried Qt WebKit and HTML5 geolocation, but not work.
I tried it's the qt5 position api support for desktop app(like mac or windows), but the answer is on the QT APIs, I believe it is possible to customize the "event" in some way, as is done using qwebkitplatformplugin to customize some features of qtwebkit (MultipleSelections, Notifications, Haptics, TouchInteraction, FullScreenVideoPlayer and SpellChecker).
I tried set PermissionGrantedByUser, but not work:
void WebPage::permissionRequested(QWebFrame* frame, Feature feature)
{
switch (feature) {
case Geolocation:
qDebug() << "GEO-Location: PermissionGrantedByUser";
setFeaturePermission(frame, feature, PermissionGrantedByUser);
break;
default:
qDebug() << "";
}
}
I tried add this QT += positioning, but not work
I tried add this TARGET.CAPABILITY += NetworkServices Location, but not work, I believe this is for smartphones, like Symbian.
Event displayLocation and watchPosition are never fired and using {timeout: ...} it shows the message Timeout expired:
<script>
function displayError(err) {
document.getElementById("geo").innerHTML = ("Error Code: " + err.code +
" / msg: " + err.message);
}
function displayLocation(position) {
document.getElementById("geo").innerHTML = [
"latitude:" + position.coords.latitude,
"longitude:" + position.coords.longitude
].join(", ");
}
function getMyLocation() {
if (navigator.geolocation) {
navigator.geolocation.watchPosition(function(a, b, c) {
console.log(a, b, c);
document.getElementById("geo").innerHTML = "Testando...";
});
navigator.geolocation.getCurrentPosition(displayLocation, displayError, {
enableHighAccuracy: false,
timeout: 10000,
maximumAge: 0
});
} else {
document.getElementById("geo").innerHTML = "No geolocation support";
}
}
window.onload = function() {
getMyLocation();
};
</script>
<div id="geo"></div>
I believe that I have to build a library and put in the qtDir/compiler/plugins/position folder, but do not know where to start.
How can I do this?
Or is it possible to customize the event and send coordinates of a 3rdparty lib (I'm not asking for a library and I'm not asking for alternatives in javascript) in response to the navigator.geolocation.getCurrentPosition?
Extra info about
If use QT_DEBUG_PLUGINS=1 in debug mode Application Output return this (note that the first line is generated by WebPage::permissionRequested):
GEO-Location: PermissionGrantedByUser
QFactoryLoader::QFactoryLoader() checking directory path "C:/Qt5.4.0/5.4/mingw491_32/plugins/position" ...
QFactoryLoader::QFactoryLoader() looking at "C:/Qt5.4.0/5.4/mingw491_32/plugins/position/qtposition_positionpoll.dll"
Found metadata in lib C:/Qt5.4.0/5.4/mingw491_32/plugins/position/qtposition_positionpoll.dll, metadata=
{
"IID": "org.qt-project.qt.position.sourcefactory/5.0",
"MetaData": {
"Keys": [
"positionpoll"
],
"Monitor": true,
"Position": false,
"Priority": 1000,
"Provider": "positionpoll",
"Satellite": false
},
"className": "QGeoPositionInfoSourceFactoryPoll",
"debug": false,
"version": 328704
}
"The plugin 'C:/Qt5.4.0/5.4/mingw491_32/plugins/position/qtposition_positionpoll.dll' uses incompatible Qt library. (Cannot mix debug and release libraries.)"
not a plugin
QFactoryLoader::QFactoryLoader() looking at "C:/Qt5.4.0/5.4/mingw491_32/plugins/position/qtposition_positionpolld.dll"
Found metadata in lib C:/Qt5.4.0/5.4/mingw491_32/plugins/position/qtposition_positionpolld.dll, metadata=
{
"IID": "org.qt-project.qt.position.sourcefactory/5.0",
"MetaData": {
"Keys": [
"positionpoll"
],
"Monitor": true,
"Position": false,
"Priority": 1000,
"Provider": "positionpoll",
"Satellite": false
},
"className": "QGeoPositionInfoSourceFactoryPoll",
"debug": true,
"version": 328704
}
Got keys from plugin meta data ("positionpoll")
QFactoryLoader::QFactoryLoader() checking directory path "C:/projects/webview-example/debug/position" ...

How to move GYP target to a separate include file

I want many gyp scripts to have a common target. So I decided to move it to a separate include file. Simplest test-case that produces an error:
foo.gyp
{
'includes' : [
'bar.gypi',
],
}
bar.gypi
{
'targets': [
{
'target_name' : 'phony',
'type' : 'none',
'actions' : [
{
'action_name' : '_phony_',
'inputs' : ['',],
'outputs' : ['',],
'action' : ['_phony_',],
'message' : '_phony_',
},
],
},
],
}
Produces error:
IndexError: string index out of range while reading includes of
foo.gyp while tr ying to load foo.gyp
Some observations:
If I delete actions from target, everything parses well
If I move targets (with actions) to foo.gyp, everything parses well
Am I doing something wrong?
It looks like the "outputs" list can not be empty or contain an empty string:
# gyp/make.py:893
self.WriteLn("%s: obj := $(abs_obj)" % QuoteSpaces(outputs[0]))
You may have empty inputs but in this case the phony action will shoot only once. I haven't found any mentions of phony actions in the GYP documentation, but I have the following variant working:
# bar.gypi
{
'targets': [
{
'target_name' : 'phony',
'type' : 'none',
'actions' : [
{
'action_name' : '_phony_',
'inputs' : ['./bar.gypi'], # The action depends on this file
'outputs' : ['test'], # Some dummy file
'action' : ['echo', 'test'],
'message' : 'Running phony target',
},
],
},
],
}
I could try to find a better way if you tell me more about the task you are trying to solve.