how NDK build so and link in same Android.mk? - android-ndk

An Android project compiles 2 so files at the same time. We call him the first and the second SO. I want to call the functions in the first SO in the second SO. How do I do that?
file content and tree is followed:
jni
|-Android.mk
|-myfiles2.c
|-------firstlibdir
|—------|-myfiles1.c
|-------|-Android.mk
|
myfiles1.c :
int func1(){
return 123;
}
myfiles2.c :
int func2(){
func1(); // this function in first so files
return 0;
}
first so file build
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := module_lib1
LOCAL_SRC_FILES := myfiles1.c
LOCAL_LDLIBS += -llog
include $(BUILD_SHARED_LIBRARY)
second so file build
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := module_lib2
LOCAL_SRC_FILES := myfiles2.c
LOCAL_LDLIBS += -llog
LOCAL_SHARED_LIBRARIES := module_lib1 // this is not work because fisrt file not build finish
include $(BUILD_SHARED_LIBRARY)
include firstlibdir/Android.mk
my question is how to first build libmodule_lib1.so and use in second Android.mk

Related

PopString and PushString methods in the assembled dll

During the execution of the dll the installer crashes on these methods
The methods are taken from the file nsis.pas
function PopString(): string;
var
th: pstack_t;
begin
if integer(g_stacktop^) <> 0 then begin
th := g_stacktop^;
Result := PChar(#th.text);
g_stacktop^ := th.next;
GlobalFree(HGLOBAL(th));
end;
end;
procedure PushString(const str: string='');
var
th: pstack_t;
begin
if integer(g_stacktop) <> 0 then begin
th := pstack_t(GlobalAlloc(GPTR, SizeOf(stack_t) + g_stringsize));
lstrcpyn(#th.text, PChar(str), g_stringsize);
th.next := g_stacktop^;
g_stacktop^ := th;
end;
end;
It looks like nsis.pas is perhaps not compatible with every Delphi version when compiling as Unicode. You did not specify your version so I don't know if your string type is AnsiString or WideString or UnicodeString.
I don't really know Pascal/Delphi anymore but I was able to get it working in FreePascal with this version. I'll try to fix it for the next release.
Make sure UNICODE is defined when using this in a Unicode plug-in.
The problem was very easy to solve
It was necessary to call Init() from nsis.pas
and then everything worked

Evaluate a collection of data from preprocessor on run time in Inno Setup Pascal Script

I am trying to get Inno Setup define value in Code section but not with {#VersionTool1}. I need to pass defined name dynamically, because there are a lot of them (I want to avoid large switch case). I tried SetupSetting but it's not in Setup section (it's before it). Is there any way to do this?
#define VersionTool1 2019.01.1111
#define VersionTool2 2020.02.2111
...
[Code]
procedure SetSelectedTool(ToolName: String);
var
CurrentTool: string;
begin
...
CurrentTool := 'Version' + ToolName;
CurrentToolVersion := {#CurrentTool};
...
end;
Value of local variable CurrentTool wil for example be 'VersionTool1' and I want to get value of VersionTool1 preprocessor variable which is 2020.02.2111.
It's not possible, see Evaluate preprocessor macro on run time in Inno Setup Pascal Script.
But there are other solutions.
For example:
[Code]
var
ToolNames: TStringList;
ToolVersions: TStringList;
function InitializeSetup(): Boolean;
begin
ToolNames := TStringList.Create;
ToolVersions := TStringList.Create;
#define AddToolVersion(Name, Version) \
"ToolNames.Add('" + Name + "'); ToolVersions.Add('" + Version +"');"
#emit AddToolVersion('Tool1', '2019.01.1111')
#emit AddToolVersion('Tool2', '2020.02.2111')
{ ... }
Result := True;
end;
(of course, the above makes sense only if you actually do not hardcode the version numbers, but use a code that only a preprocessor can do – something like GetStringFileInfo, what I've understood from your comments that you plan to)
And then you can have a function like:
function GetToolVersion(ToolName: string): string;
var
I: Integer;
begin
I := ToolNames.IndexOf(ToolName);
if I >= 0 then Result := ToolVersions[I];
end;
Another similar questions:
Array Variables and dynamic access in [Code] section
Scripting capabilities in the Registry section

Using a standard Inno Setup message in the Run entry description

There is a related question for those who are interested here. I was encouraged to ask one of the questions separately.
So I have this [Run] code:
Filename: "{cmd}"; Parameters: "/C exit"; Description: "Exit Setup"; \
Flags: nowait postinstall runasoriginaluser unchecked skipifsilent; Check: IsWin64
It works well. It shows the following window at the end of the installation:
But the problem is that the wording Exit Setup is hard coded in English. Now, I have looked at the default.isl file and located:
ExitSetupTitle=Exit Setup
ClickFinish=Click Finish to exit Setup.
I don't know if I should be using either of these messages. It makes sense to me to use the ClickFinish because that is what the user will be doing.
But I can't work out how to use that message in the run statement.
Update
I have modified the supplied answer to:
function GetClickFinishSetupMessage(Param: string): string;
var
I: integer;
S1: string;
S2: string;
begin
S1 := SetupMessage(msgClickFinish);
I := Length(S1);
S2 := Copy(S1, I-1, 1);
if(S2 = '.') then
S1 := Delete(S1, I-1, 1);
end;
result := S1;
end;
So I could remove the final period. But it will not compiled. It says there is a mismatch for the third parameter of Delete.
Use SetupMessage support function from a scripted constant:
[Run]
Filename: ...; Description: {code:GetClickFinishSetupMessage}
[Code]
function GetClickFinishSetupMessage(Param: string): string;
begin
Result := SetupMessage(msgClickFinish);
{ Drop trailing dot, if any }
if Copy(Result, Length(Result), 1) = '.' then
SetLength(Result, Length(Result) - 1);
end;

Inno Setup: Reading a file from installer during uninstallation

Using the following code during uninstall
BitmapImage := TBitmapImage.Create(InstallTopPanel);
BitmapImage.AutoSize := True;
BitmapImage.Bitmap.LoadFromFile(
ExpandConstant( '{tmp}\WizardSmallImageFile.bmp') );
BitmapImage.Parent := InstallTopPanel;
BitmapImage.Top := (InstallTopPanel.ClientHeight - 58) / 2;
BitmapImage.Left := InstallTopPanel.ClientWidth - 55 - 10;
I get an error:
Exception : can not open file.
C:\users\xyz\AppData\Local\Temp\is-U3Q8P.tmp\WizardSmallImageFile.Bmp.
File not found.
I tried also to use ExtractTemporaryFile before I call LoadFromFile which is not supported during uninstall.
ExtractTemporaryFile('WizardSmallImageFile.bmp');
So, the question, how to view an image or specifically WizardSmallImageFile during uninstall?
My code above builds a custom form with a custom panel. Like here: Inno Setup Uninstall some components only.
Correct, the ExtractTemporaryFile extracts files from the installer. Therefore it cannot work in the uninstaller as the installer is not available anymore.
Also note that you cannot extract the file referenced to by the WizardSmallImageFile directive from the installer anyway. You have to add your own copy.
If you need to use some file during uninstallation, you have to install it in the installer and then use the installed copy in the uninstaller.
[Files]
Source: "WizardSmallImageFile.bmp"; DestDir: "{app}";
[Code]
function InitializeUninstall(): Boolean;
begin
...
BitmapImage := TBitmapImage.Create(...);
...
BitmapImage.Bitmap.LoadFromFile(
ExpandConstant('{app}\WizardSmallImageFile.bmp'));
...
end;
If you want to do without installing the file, you can embed the image data into the code.
Unfortunately the Unicode Inno Setup is quite limited when dealing with binary data as it tends to try to convert everything to UTF-8. But after numerous tries I've ended up with some working code.
Note that the code uses a PowerShell code invoked from Inno Setup preprocessor – The PowerShell is needed on compile-time only, not on run/install-time.
Add this code somewhere to the front of your [Code] section:
function CryptStringToBinary(
sz: string; cch: LongWord; flags: LongWord; binary: string; var size: LongWord;
skip: LongWord; flagsused: LongWord): Integer;
external 'CryptStringToBinaryW#crypt32.dll stdcall';
const
CRYPT_STRING_HEX = $04;
procedure WriteBinaryStringToStream(S: string; Stream: TStream);
var
Buffer: string;
Size: LongWord;
Len: Integer;
begin
Len := Length(S);
SetLength(Buffer, (Len div 4) + 1);
Size := Len div 2;
if (CryptStringToBinary(S, Len, CRYPT_STRING_HEX, Buffer, Size, 0, 0) = 0) or
(Size <> Len div 2) then
begin
RaiseException('Error decoding binary string');
end;
Stream.WriteBuffer(Buffer, Size);
end;
function StreamFromBinaryString(S: string): TStream;
begin
Result := TStringStream.Create('');
WriteBinaryStringToStream(S, Result);
Result.Position := 0;
end;
procedure LoadBitmapFromBinaryString(Bitmap: TBitmap; S: string);
var
Stream: TStream;
begin
Stream := StreamFromBinaryString(S);
try
Bitmap.LoadFromStream(Stream);
finally
Stream.Free;
end;
end;
procedure SaveBinaryStringToFile(FileName: string; S: string);
var
Stream: TStream;
begin
Stream := TFileStream.Create(FileName, fmCreate);
try
WriteBinaryStringToStream(S, Stream);
finally
Stream.Free;
end;
end;
#define FileToBinaryString(str FileName) \
Local[4] = ExtractFileName(FileName), \
Local[0] = AddBackslash(GetEnv("TEMP")) + Local[4] + ".pas", \
Local[1] = \
"-ExecutionPolicy Bypass -Command """ + \
"Write-Host 'Generating code for " + Local[4] + "'; " + \
"$bytes = [System.IO.File]::ReadAllBytes('" + FileName + "'); " + \
"$s = '''' + (($bytes | foreach { $_.ToString('X2') }) -join '') + ''''; " + \
"Set-Content -Path '" + Local[0] + "' -Value $s;" + \
"""", \
Exec("powershell.exe", Local[1], SourcePath, , SW_HIDE), \
Local[2] = FileOpen(Local[0]), \
Local[3] = FileRead(Local[2]), \
FileClose(Local[2]), \
DeleteFileNow(Local[0]), \
Local[3]
And then you can use the FileToBinaryString preprocessor macro to convert a file on compile-time (or more precisely, when pre-processing) to a hex string like:
'4D5A50000200000004000F00FFFF0000B800000....'
On runtime, you use the hex string with some of the functions WriteBinaryStringToStream, StreamFromBinaryString, LoadBitmapFromBinaryString or SaveBinaryStringToFile.
In your case you will use:
LoadBitmapFromBinaryString(
BitmapImage.Bitmap, {#FileToBinaryString("C:\path\WizModernSmallImage.bmp")});
On compile-time, this gets converted to a code like:
LoadBitmapFromBinaryString(
BitmapImage.Bitmap, '4D5A50000200000004000F00FFFF0000B800000....');
The pre-processor/Pascal compiler has a limit of about 100M characters for a string. Though you will actually first hit a [compile-time] memory limit of the PowerShell script for files larger than about 20-30 MB. Though even for smaller sizes (larger than few MBs), the compile-time time performance of the PowerShell script is bad. The script can be optimized significantly though.
Due to the hex encoding, the size of the installer increases twice as much. This could be improved by using some more efficient encoding, like Base64 (CRYPT_STRING_BASE64). The code section is not even compressed too, comparing to files included with the [Files] section (not a problem for images as these are compressed already, but makes a difference with DLLs for example).
The code requires the Unicode version of Inno Setup. You should not use the Ansi version anyway, in the 21st century. Though ironically, implementing this in the Ansi version would be way easier. See my answer to Writing binary file in Inno Setup for a use of the CryptStringToBinary that's compatible with both Ansi and Unicode version of Inno Setup. Though in the Ansi version you can actually do with a binary string, instead of a hex string.

how to configure make file to find header files in other directories?

I keep getting this error from my Android.mk file:
/home/sansari/mytree2/tbt/app/app.c:23:19: fatal error: debug.h: No such file or directory
#include <debug.h>
What I am trying to do is to import the source from another directory into my jni project. So I do not even have any statement for building app.c; it is being done by make implicit rules. Whist is great. My problem seems to be not knowing how to tell make hey look in the ../include directory for debug.h. That would be /home/sansari/mytree2/tbt/include. How do I do this please? What other information do you need to help me?
In order to provide a point of reference to you I need to add I am trying to run make from:
/home/sansari/AndroidStudioProjects/ThirdNDK/app/src/main/jni
I did issue the -p option to make; actually I am running ndk-build command which is a shell that runs make. And it seems like make is processing .mk fiels in my sources directories. Is it possible for make to do this implicitly without me adding an include for other make files? Here is what I have done to create my source files; it looks like make automatically finds .mk files in these directories and runs them:
FILE_LIST := $(wildcard /home/sansari/mytree2/tbt/*.c)
FILE_LIST += $(wildcard /home/sansari/mytree2/tbt/**/*.c)
FILE_LIST += $(wildcard /home/sansari/mytree2/tbt/**/**/*.c)
FILE_LIST += $(wildcard /home/sansari/mytree2/tbt/**/**/**/*.c)
FILE_LIST += $(wildcard /home/sansari/mytree2/tbt/**/**/**/**/*.c)
FILE_LIST += $(wildcard /home/sansari/mytree2/tbt/**/**/**/**/**/*.c)
LOCAL_MODULE := HelloJNI
LOCAL_SRC_FILES := $(FILE_LIST:$(LOCAL_PATH)/%=%) HelloJNI.c
Just an update on this issue; I found out that it is possible for the VPATH statement work ok, and actually find the file. But then the compiler may not see it. I am still reading and digging, but if anyone can help I would certainly appreciate it.
#ognian - Hey thanks. I tried your suggestion and it does not seem to resolve my issue. I printed the content of LOCAL_C_FLAGS just to validate. Here is what I have:
/home/sansari/AndroidStudioProjects/ThirdNDK/app/src/main/jni/Android.mk:15: value of LOCAL_CFLAGS -I/home/sansari/mytree2/lib/include/debug.h
/home/sansari/AndroidStudioProjects/ThirdNDK/app/src/main/jni/Android.mk:15: value of LOCAL_CFLAGS -I/home/sansari/mytree2/lib/include/debug.h
/home/sansari/AndroidStudioProjects/ThirdNDK/app/src/main/jni/Android.mk:15: value of LOCAL_CFLAGS -I/home/sansari/mytree2/lib/include/debug.h
/home/sansari/AndroidStudioProjects/ThirdNDK/app/src/main/jni/Android.mk:15: value of LOCAL_CFLAGS -I/home/sansari/mytree2/lib/include/debug.h
/home/sansari/AndroidStudioProjects/ThirdNDK/app/src/main/jni/Android.mk:15: value of LOCAL_CFLAGS -I/home/sansari/mytree2/lib/include/debug.h
/home/sansari/AndroidStudioProjects/ThirdNDK/app/src/main/jni/Android.mk:15: value of LOCAL_CFLAGS -I/home/sansari/mytree2/lib/include/debug.h
/home/sansari/AndroidStudioProjects/ThirdNDK/app/src/main/jni/Android.mk:15: value of LOCAL_CFLAGS -I/home/sansari/mytree2/lib/include/debug.h
[arm64-v8a] Compile : HelloJNI <= app.c
/home/sansari/mytree2/tbt/app/app.c:23:19: fatal error: debug.h: No such file or directory
#include <debug.h>
^
compilation terminated.
make: *** [/home/sansari/AndroidStudioProjects/ThirdNDK/app/src/main/obj/local/arm64-v8a/objs/HelloJNI//home/sansari/mytree2/tbt/app/app.o] Erro
r 1
From what I read online, it seems to me I can point to the right directory but I do not know what else needs to happen for make to see it. There was also some comments online about the possibility of the compiler not seeing the required file. I think I need to learn more about what happens after I load variables with the right path. I looked into vpath and VPATH, but according to make manual the directory portion of the path is removed by make. So I tried creating a variable and loading the path of all of my header files into it. I then copied the content into GPATH variable, which according to the manual, would not get rid of the directory paths. But I guess I don't know what else I need to do. Here is my Androdi.mk
LOCAL_PATH := $(call my-dir)
#.INCLUDE_DIRS=make arch
#TLK_DIR = ../../../../../..$(LOCAL_PATH)/mytree2/tbt
include $(CLEAR_VARS)
#-I.$(LOCAL_PATH)../../../../../../mytree2/tbt/include/ \
SOURCES = /home/sansari/mytree2/tbt/%.c
#$(warning value of SOURCES is $(SOURCES))
INCLUDE_DIRECTORIES = /home/sansari/mytree2/lib/include
vpath %.h $(INCLUDE_DIRECTORIES)
CFLAGS += $(addprefix -I ,$(INCLUDE_DIRECTORIES))
#$(warning value of CFLAGS is $(CFLAGS))
LOCAL_CFLAGS += -I/home/sansari/mytree2/lib/include/debug.h
$(warning value of LOCAL_CFLAGS $(LOCAL_CFLAGS))
#override CFLAGS += $(patsubst %,-I%,$(subst :, ,$(VPATH)))
HEATHER_LIST := $(wildcard /home/sansari/mytree2/tbt/*.h)
FILE_LIST := $(wildcard /home/sansari/mytree2/tbt/*.c)
#$(warning value of HEATHER_LIST is $(HEATHER_LIST))
#$(warning value of FILE_LIST is $(FILE_LIST))
FILE_LIST += $(wildcard /home/sansari/mytree2/tbt/**/*.c)
HEATHER_LIST += $(wildcard /home/sansari/mytree2/tbt/**/*.h)
#$(warning value of FILE_LIST is $(FILE_LIST))
#$(warning value of HEATHER_LIST is $(HEATHER_LIST))
#FILE_LIST += $(wildcard /home/sansari/mytree2/tbt/**/*.h)
FILE_LIST += $(wildcard /home/sansari/mytree2/tbt/**/**/*.c)
HEATHER_LIST += $(wildcard /home/sansari/mytree2/tbt/**/**/*.h)
#$(warning value of HEATHER_LIST is $(HEATHER_LIST))
#$(warning value of FILE_LIST is $(FILE_LIST))
#FILE_LIST += $(wildcard /home/sansari/mytree2/tbt/**/**/*.h)
FILE_LIST += $(wildcard /home/sansari/mytree2/tbt/**/**/**/*.c)
HEATHER_LIST += $(wildcard /home/sansari/mytree2/tbt/**/**/**/*.h)
#$(warning value of FILE_LIST is $(FILE_LIST))
#$(warning value of HEATHER_LIST is $(HEATHER_LIST))
#FILE_LIST += $(wildcard /home/sansari/mytree2/tbt/**/**/**/*.h)
FILE_LIST += $(wildcard /home/sansari/mytree2/tbt/**/**/**/**/*.c)
HEATHER_LIST += $(wildcard /home/sansari/mytree2/tbt/**/**/**/**/*.h)
#$(warning value of HEATHER_LIST is $(HEATHER_LIST))
#$( warning value of FILE_LIST is $(FILE_LIST))
#FILE_LIST += $(wildcard /home/sansari/mytree2/tbt/**/**/**/**/*.h)
FILE_LIST += $(wildcard /home/sansari/mytree2/tbt/**/**/**/**/**/*.c)
HEATHER_LIST += $(wildcard /home/sansari/mytree2/tbt/**/**/**/**/**/*.h)
#$( warning value of FILE_LIST is $(FILE_LIST))
#$(warning value of HEATHER_LIST is $(HEATHER_LIST))
GPATH = $(HEATHER_LIST)
#$(warning ******The Value of GPATH is $(GPATH))
#FILE_LIST += $(wildcard /home/sansari/mytree2/tbt/**/**/**/**/**/*.h)
LOCAL_MODULE := HelloJNI
LOCAL_C_INCLUDES := $(LOCAL_PATH)/HEATHER_LIST
LOCAL_SRC_FILES := $(FILE_LIST:$(LOCAL_PATH)/%=%) HelloJNI.c
# Build all java files in the java subdirectory
#LOCAL_MODULE := HelloJNI
#LOCAL_SRC_FILES := HelloJNI.c
# Tell it to build an APK
include $(BUILD_SHARED_LIBRARY)
#include $(TLK_DIR)/makefile
You need to provide the header lookup option:
LOCAL_CFLAGS += -I{your-header-path-here}

Resources