How does import find the file path in Kotlin? - kotlin

I've read the Kotlin doc (https://kotlinlang.org/docs/packages.html), and I understood that, when importing a package, the package name does not need to match the folder's path that stores the package (unlike what happens in Java).
I don't have issues creating a package and importing it into other classes.
What I'd like to understand, is how the compiler can find the file to import?
For example:
if a file import animals.mammals.cats.* :
import animals.mammals.cats.*
...
the entities to import do not need to be stored in the file /animals/mammals/cats.kt, as long as the package name is "animals.mammals.cats":
package animals.mammals.cats
...
This Kotlin file could be stored in src/animals/kittens for example.
In other words, how import can locate the file/s to load since the package name does not help?
Thanks!

TL;DR: the compiler is given the paths to all files to compile and to all dependencies, and therefore knows about all available packages and the declarations they contain.
First, note that the import statement itself is not really the most important. It's just a convenient syntax to avoid having to specify the package everywhere throughout the file. But technically you don't need to import anything to be able to use declarations from outside the current file - you can just use their fully qualified name (a.k.a FQN) which is the package name + . + the name of the declaration.
Now, on to your question. When you run the compiler, you provide the paths to the complete set of files to be compiled at the same time: you compile a module, not a single file. Therefore, it has access to all declarations in all those files and maintains its own data structures about the available classes and top-level functions, and all symbols in general. So it can store and find declarations using just their FQN. (DISCLAIMER: I'm no expert and I don't actually know how it's done internally, but I'm just guessing that conceptually it's like storing a big mapping between FQN and the information about the corresponding declaration.)
If the declaration you use is not in the set of files being compiled, it must be in one of your dependencies. You can tell the compiler about the available dependencies by specifying the list of jars containing their already compiled classes. This list of all classes available at compile time is called the compile classpath. This is why the tool you use to build your project (for instance, Gradle or your IDE) needs to know about those dependencies, so it can put their declarations on the compile classpath when calling the compiler for you. Then, just like declarations that are being compiled, the ones from the compile classpath can be easily looked up by the compiler (the path has been given to the compiler as an argument).
Now, when you actually run your compiled program, at least on the JVM, the classes required must be placed on the runtime classpath - a set of classes given to the java program. Finding those declarations while the program runs is done by classloaders. There are multiple classloaders, organized in a hierarchy, but there is no need to go into details here. Basically, each time a class is used for the first time while your program is running, one classloader will be asked to load that class into memory. There are different implementations of classloaders, but one of the most common is the URLClassLoader which is given the URLs of some jars that contain classes, and knows how to read classes from these jars into memory on-demand.

Related

How to link a shared library without having to export its internal targets

The following repro cmake project fail to configure. The goal is to create a shared library that internally consists of a couple of static libraries. I want the internal symbols and include paths etc to be exported from the shared library. To do that I make the internal libs PUBLIC link libraries. But then cmake tells me I need to export my target. I don't want to "pollute" my package config with a bunch of internal targets. Is there no way to "merge" internal targets (static libs) into the public exported target (shared lib) or hide it in the config targets file?
The SystemC::systemc imported target does not show up in my target file and it also don't generate any error. I assume that is because this target is already exported in its own package? If so, would that mean I need to make my internal libs packages and so imported targets to make them go away from my exported targets list?
cmake_minimum_required(VERSION 3.16)
project(mylib)
find_package(SystemCLanguage 2.3.3 CONFIG REQUIRED)
add_library(mysublib STATIC mysublib.cpp)
add_library(mylib SHARED mylib.cpp)
target_link_libraries(mylib
PUBLIC SystemC::systemc
PUBLIC mysublib
)
export(
TARGETS mylib
NAMESPACE MyLib::
FILE MyLibTargets.cmake
)
Error generated at configure
CMake Error in CMakeLists.txt:
export called with target "mylib" which requires target "mysublib" that is
not in any export set.
The goal is to create a shared library that internally consists of a couple of static libraries. I want the internal symbols and include paths etc to be exported from the shared library. To do that I make the internal libs PUBLIC link libraries.
So, first, I'll note that PUBLIC has nothing at all to do with symbol visibility. Your example mysublib doesn't have any INTERFACE properties, so you could make it PRIVATE to mylib and avoid the need to export mysublib.
However, if you do need mysublib in the INTERFACE of mylib, then you do need to export it, period. There is no way to, as you say "'merge' internal targets [...] into the public exported target [...] or hide it in the config targets file". But this is also not a real problem.
If you're concerned about people relying on mysublib, then you can set the EXPORT_NAME property of mysublib to something that indicates it's not meant to be used, like _private_mysublib:
set_target_properties(mysublib PROPERTIES EXPORT_NAME _private_mysublib)
If you want to be really aggressive about it, you could even make the name random:
string(RANDOM LENGTH 12 mysublib_export)
set_target_properties(mysublib PROPERTIES EXPORT_NAME "x${mysublib_export}")
Prepending an x makes sure it doesn't start with a number. There is also a remote chance of collision if you do this a lot. If you want to be absolutely safe, you should write a function that records the names it's already returned in a global property and tries again if it chooses a collision.
The SystemC::systemc imported target does not show up in my target file and it also don't generate any error. I assume that is because this target is already exported in its own package? If so, would that mean I need to make my internal libs packages and so imported targets to make them go away from my exported targets list?
You are correct: because SystemC::systemc is imported, it does not need to be (and in fact cannot be) re-exported. You're expected to call find_dependency(SystemCLanguage 2.3.3) in your MyLibConfig.cmake file, both within the build tree (export) and after install (install(EXPORT)).
If you want this behavior to apply to mysublib, then yes, you will need to split your projects apart. I don't see a compelling reason to do that, though. Either make mysublib PRIVATE or just live with it being renamed in your package config. Targets aren't precious and they're namespaced, so there's no real reason to worry.

How to find source file path by compiled class file programmatically in kotlin?

In kotlin, package can be declared randomly, which is not relative to source file path, then compiler will generate class file in package folder. How to find source file path by compiled class file programmatically?
Example:
package kt.notsamepackage_another
class NotSamePackageKotlin {
fun call() {
}
}
NotSamePackageKotlin.class will be generated in folder: ../kt/notsamepackage_another, but source file may be in ../kt/notsamepackage.
I tried these methods:
decompile class file. But source file path can't be found in byte code
adjust kotlin compiler parameters. I want find a parameter to output a mapping contains path relationship, but nothing was found
traverse source folder recursively. This method is not efficient, it's the last choice.
Is there any method more efficient?
I don't think this is possible.  If the full source path isn't compiled into the bytecode, then there's no way to find it programmatically.  And I'm not aware of any compiler parameters which would do this.  (The simple filename is often compiled in, of course; that's how stack traces can show the filename and line number at which an exception was thrown.  But not the full path.)
Even your third method won't work in general; programs aren't usually run on the same machine on which they were compiled, so your code would have to make some very risky assumptions.
But I'm curious as to why you'd want to know this at all.  What problem are you trying to solve?

Do Kotlin's access modifiers mean the same thing as in Java?

Kotlin has 3 keywords for access: public, private and protected. Do they mean the same thing as in Java, or are there differences? Also, is internal the same as package private? I keep reading about "modules" in Kotlin, and I'm not sure if that's just another word for "package".
Kotlin's access modifiers do not always mean the same thing as in Java. For example, Kotlin allows protected members in interfaces while Java does not.
Modules are compile-time only entities. They group source files and declare dependencies for them (binary libraries and other modules). A module is a unit of compilation, i.e. all of its files are compiled together (in fact there is file-by-file incremental compilation, but its effect must be the same as re-compiling the whole module).
For example, each Maven pom implicitly declares a module, and IDE has modules in the Project View and Project Structure.

What does it mean for Scheme library to be *loaded*? When are Scheme libraries *loaded*?

I am studying the Revised7 Report on the Algorithmic Language Scheme. My question is on section 5.6 Libraries.
In this section, it says:
When a library is loaded, its expressions are executed in textual order. If a library's definitions are referenced in the expanded form of a program or library body, then that library must be loaded before the expanded program or library body is evaluated. This rule applies transitively. If a library is imported by more than one program or library, it may possibly be loaded additional times.
What is this supposed to mean? Does it mean that a library is loaded only if an imported identifier is actually being referenced or already when the library is part of an import set of an expanded program or library? If the same library is being referenced by two other library imported by the same program, is the library loaded twice or just once?
As the loading of a library may have side-effects due to the execution of its expressions, the answers to these questions seem important to me. Also, do share the two libraries that import a third library its internal global variables?
I have done some experiments with chibi-scheme: Per program, chibi-scheme loads every library only once and even if none of its exported identifiers are actually referenced. In fact, this looks like a sensible and easily implementable thing to me.
P.S.: There is another point where I think the specification is a bit vague: What happens if, in a program, an import set imports an identifier named import? Does it mean that an immediately following line (import ...) is interpretated as a command or definition (depending on what the imported identifier import stands for) or still as an import set?
P.P.S.: What is even the reason for allowing more than one import declaration in a top-level program?
Let me attempt to answer each of your questions one-at-a-time. Also, if it would help, here is a link to the meta-language used to implement libraries in chibi scheme.
A library is loaded when it is imported via an import statement.
If a library's definitions are referenced in the expanded form of a program or library body, then that library must be loaded before the expanded program or library body is evaluated.
This just means that the library must be loaded before its definitions are referenced (or it would be an error, since the definitions would not be found).
If a library is imported by more than one program or library, it may possibly be loaded additional times.
This is implementation-dependent, so your library code should not make assumptions that it will only be loaded once.
What happens if, in a program, an import set imports an identifier named import?
Most likely, the new import identifier would shadow or replace the import, so that any import statements in the same scope would no longer work as expected. This might be implementation-dependent - if import is implemented as a special form then it would not be overridden by a newly introduced identifier.

Xcode xcconfig: Configuring a dependency based on the target

In the quest to resolve the Objective-C namespace issue I'd like to experiment with prefixing a dependency's Objective-C classes based on the target being built.
As an example, suppose I have in my shared library (ObjCStaticLib) a class (CWindow). I have two plugins (A and B) that will use this CWindow. To avoid A's CWindow from colliding with B's CWindow, I want to prefix the CWindow class name at compile time, so A's CWindow becomes ACWindow and B's becomes BCWindow.
I'm looking for a way to communicate to ObjCStaticLib at compile time what prefix it should use to compile itself with. I'm thinking about using xcconfigs to specify a preprocessor macro that the leaf target customizes and that ObjCStaticLib uses. However, I'm not aware of a way for a target to "communicate" with a dependency like that.
I can modify all the sources/projects/etc involved as necessary to implement per-client namespace customization in a dependency.
Does anyone have a good solution for this?