Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[K/N] Expose program name in runtime #5281

Open
wants to merge 27 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
1ff362a
[K/N] Expose program name in runtime
vonox7 Mar 21, 2024
05d57ee
Merge branch 'refs/heads/master' into slawicek/program-name
vonox7 Apr 29, 2024
f73045e
Move programName testcase to new test infrastructure
vonox7 Apr 29, 2024
fb67427
Add testcase for calling Platform.getProgramName from within a library
vonox7 Apr 30, 2024
2703f15
Execute Kotlin executable via execv to pass custom programNames
vonox7 Apr 30, 2024
3b66b6b
Support argc=0
vonox7 Apr 30, 2024
285dd67
Merge branch 'JetBrains:master' into slawicek/program-name
vonox7 Apr 30, 2024
69e660f
Use proper executor
vonox7 May 15, 2024
a69b027
Merge remote-tracking branch 'vali/slawicek/program-name' into slawic…
vonox7 May 15, 2024
6d07cf2
Remove unneeded gradle task
vonox7 May 15, 2024
2fcf1f0
Ignore different windows path & line-endings
vonox7 May 15, 2024
3c933a7
Let linux behave the same as windows/macos
vonox7 May 26, 2024
802c8e7
Add empty program name validation
vonox7 May 26, 2024
64ffcfc
Fix testcase on windows
vonox7 May 26, 2024
2d44f5f
Add comment for argv[0] == "" check
vonox7 Jun 3, 2024
06b0d67
Add explicit return
vonox7 Jun 3, 2024
27d7688
Set return value to 1 in case of program fail
vonox7 Jun 3, 2024
fba8ce4
Remove unneeded include
vonox7 Jun 3, 2024
0aa4600
Copy programName so no need to reset it
vonox7 Jun 4, 2024
7fb104f
Merge branch 'JetBrains:master' into slawicek/program-name
vonox7 Jun 4, 2024
7868f85
Print errno for easier exec debugging
vonox7 Jun 4, 2024
6323590
Merge branch 'JetBrains:master' into slawicek/program-name
vonox7 Jun 4, 2024
e39351d
Add missing import for linux
vonox7 Jun 4, 2024
fd2ebbf
Try to update qemu
vonox7 Jun 6, 2024
d09c9f0
Revert "Try to update qemu"
vonox7 Jun 6, 2024
841f6e0
Remove include
vonox7 Jun 8, 2024
ee0ed60
Add include back
vonox7 Jun 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions kotlin-native/backend.native/tests/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,10 @@ standaloneTest("throw_from_except_constr") {
source = "runtime/exceptions/throw_from_except_constr.kt"
}

standaloneTest("program_name") {
source = "runtime/program_name/runtime_program_name.kt"
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file represents the legacy test infrastructure that we are actively trying to get rid of.

Please create a proper test class in
https://github.com/JetBrains/kotlin/tree/master/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ported the testcase to the new infrastructure.


tasks.register("vararg0", KonanLocalTest) {
source = "lower/vararg.kt"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)

import kotlin.test.*
import kotlin.native.Platform

fun main(args: Array<String>) {
// Remove path and extension (.kexe or .exe)
val programFileName = Platform.programName.substringAfterLast("/").substringBeforeLast(".")

assertEquals("program_name", programFileName)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More tests are necessary. For example, the original issue mentions a nice use case:

Build multi-call binaries. For example, busybox is a single binary that contains many tools, and decides which tool to run based on how the symbolic link is called: https://busybox.net/downloads/BusyBox.html#usage (that's how it can be so small)

So checking a case with symbolic link would also be useful.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added test for that by calling execv() in the C code. This allowed to test even more use-cases (no programName at all), while still covering the use-case of renaming/linking a binary.

2 changes: 2 additions & 0 deletions kotlin-native/runtime/src/launcher/cpp/launcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ using namespace kotlin;
//--- Setup args --------------------------------------------------------------//

OBJ_GETTER(setupArgs, int argc, const char** argv) {
kotlin::programName = argv[0];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is argv[0] guaranteed to live long enough? What will happen if some code accesses kotlin::programName after the main function finishes?
Is argv guaranteed to always have at least one element?

Copy link
Contributor Author

@vonox7 vonox7 Apr 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. programName will now be set to null before argv leaves scope. I could not find a definite answer if it would be guaranteed to live long enough, so I opted for the safe choice.
  2. Theoretically it is guaranteed by the POSIX standard. However if it has 0 arguments, the code 1 line below would have crashed. I also added a testcase for argc=0, and added support for it via std::max(0, ...). So now kotlin executables don't crash on startup when they are launched in a non posix compatible way.


// The count is one less, because we skip argv[0] which is the binary name.
ObjHeader* result = AllocArrayInstance(theArrayTypeInfo, argc - 1, OBJ_RESULT);
ArrayHeader* array = result->array();
Expand Down
6 changes: 6 additions & 0 deletions kotlin-native/runtime/src/main/cpp/Runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ bool kotlin::initializeGlobalRuntimeIfNeeded() noexcept {
return true;
}

const char* kotlin::programName = nullptr;

extern "C" {

RUNTIME_NOTHROW void AppendToInitializersTail(InitNode *next) {
Expand Down Expand Up @@ -335,6 +337,10 @@ KBoolean Konan_Platform_isFreezingEnabled() {
return kotlin::compiler::freezingChecksEnabled();
}

OBJ_GETTER0(Konan_Platform_getProgramName) {
RETURN_RESULT_OF(CreateStringFromCString, kotlin::programName)
}

bool Kotlin_memoryLeakCheckerEnabled() {
return g_checkLeaks;
}
Expand Down
3 changes: 3 additions & 0 deletions kotlin-native/runtime/src/main/cpp/Runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "Porting.h"
#include "Memory.h"
#include "KString.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems unused.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.


#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -50,6 +51,8 @@ namespace kotlin {
// Returns `true` if initialized.
bool initializeGlobalRuntimeIfNeeded() noexcept;

extern const char* programName;

}

#endif // RUNTIME_RUNTIME_H
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ public object Platform {
public val isFreezingEnabled: Boolean
get() = Platform_isFreezingEnabled()

/**
* Representation of the name used to invoke the program executable.
*/
public val programName: String
get() = Platform_getProgramName()
SvyatoslavScherbina marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@qurbonzoda could you please review the stdlib change?


/**
* If the memory leak checker is activated, by default `true` in debug mode, `false` in release.
* When memory leak checker is activated, and leak is detected during last Kotlin context
Expand Down Expand Up @@ -161,6 +167,9 @@ private external fun Platform_isDebugBinary(): Boolean
@GCUnsafeCall("Konan_Platform_isFreezingEnabled")
private external fun Platform_isFreezingEnabled(): Boolean

@GCUnsafeCall("Konan_Platform_getProgramName")
private external fun Platform_getProgramName(): String

@GCUnsafeCall("Konan_Platform_getMemoryLeakChecker")
private external fun Platform_getMemoryLeakChecker(): Boolean

Expand Down