How do I split my code across multiple .ek9 files in one project?
← Getting Started · Ref: Q1380
Compiling one file compiles exactly that ONE file. `ek9 -c Main.ek9` does not look at its neighbours, so the moment a second file exists you get E50001 'not resolved' for anything declared in it - even when both files declare the SAME module.
THE SYMPTOM
Greeting.ek9 -> defines function greet() Main.ek9 -> stdout.println(greet("Steve")) ek9 -c Main.ek9 Error: E50001: 'greet' on line 8 position 21: not resolved
This is NOT a module-scoping problem and a 'references' block will not fix it. References brings in symbols from a DIFFERENT module; it does not add a file to the build. What is missing is a package that says which files the build contains.
ADD A package.ek9
Create a file declaring the same module with a 'defines package' block. Then compile THAT file:
#!ek9 defines module com.example.app defines package version <- 1.0.0-1 description <- "My app" license <- "MIT" applyStandardIncludes <- true
ek9 -C package.ek9
FIVE LEVELS, IN ORDER OF NEED
1. Single file - no package at all. Just write it and run it.
2. Several files, named explicitly - includeFiles <- [ "Greeting.ek9", "Main.ek9" ]
3. Every .ek9 in the directory - applyStandardIncludes <- true
4. Dependencies - add deps <- { "module": "version" }
5. Publishing - add publicAccess, tags, license
Most projects want level 3. The practical difference from level 2: with applyStandardIncludes you drop a new .ek9 file into the directory and it is picked up with NO edit to package.ek9, whereas includeFiles must name every file and silently omits any you forget.
WHICH ONE SHOULD I USE
Use includeFiles when you deliberately want only some files compiled. Use applyStandardIncludes for an ordinary project. They can be combined with applyStandardExcludes and excludeFiles to subtract.
RUNNING IT
Programs are run from the built artefact under .ek9/, naming the program fully qualified:
java -jar .ek9/package.jar -r com.example.app::MyProgram
Note that 'ek9 -r MyProgram package.ek9' does not work: the -r flag looks for the program in the file you name, and package.ek9 declares none.
ONE MODULE OR MANY
Files in one project may all declare the same module, or different modules. Same module means they share a scope and see each other directly. Different modules need a 'references' block to pull names across. Either way the package block is what decides which files are compiled.
See Q6 for module organisation. See Q13 for package versus module. See Q7 for dependencies. See Q805 for where test code lives.
Example
defines module qa.getting.started.multiple.files <?- This file carries a real package block. applyStandardIncludes is what makes a directory of .ek9 files into one build; without it, compiling any single file compiles only that file and its siblings' declarations are E50001 'not resolved'. -?> defines package version <- 1.0.0-1 description <- "Shows the package block that turns several files into one build" license <- "MIT" //Level 3 - every .ek9 in this directory. Drop in a new file and it is picked up //with no edit here. Level 2 would instead be: // includeFiles <- [ "Greeting.ek9", "Main.ek9" ] //which must name every file and silently omits any you forget. applyStandardIncludes <- true defines function //In a real project this would sit in its own file, say Greeting.ek9. greet() as pure -> name as String <- rtn as String: `Hello, ${name}!` defines program //And this in Main.ek9. Both declare the same module, so they see each other //directly - but ONLY because the package block puts both in the build. MultipleFilesDemo() stdout <- Stdout() stdout.println(greet("Steve")) stdout.println("Compile the package file: ek9 -C package.ek9") stdout.println("A 'references' block is for other MODULES; it does not add a file to the build")
Common mistakes
E50001 — E50001 is what the CALLER sees when a declaration is not in the build - the symptom a sibling file left out of the package produces. Renaming the declaration reproduces it inside this one file: the call still says greet(...) and no longer resolves. NOTE the package-level CAUSE is deliberately not a typicalError: a mutation of the package block cannot unresolve anything here, because this example inlines the function and the program in ONE file - so the two pairs that tried it (dropping applyStandardIncludes, and an includeFiles list missing a file) mutated text that changes nothing and silently tested nothing. That cause is taught in the prose and comments above instead. See ek9 -h E50001 for details.
Incorrect:
greetUser() as pure
Correct:
greet() as pure
Other ways to ask this
- Why does my other file's function give E50001 not resolved?
- How do I compile more than one .ek9 file together?
- What is applyStandardIncludes and when do I need it?
- How do I set up a multi-file EK9 project?
- Do I need a package.ek9 and what goes in it?
- My second file's types are not resolving - what am I missing?
- What is the difference between includeFiles and applyStandardIncludes?
- How does the EK9 compiler know which source files to build?
- How does the compiler find all my source files?
- Why is my other file not resolved?
- Why can my program not see code from the next file along?
Coming from another language?
Java: the build tool (Maven/Gradle) owns the source set - src/main/java is compiled wholesale and javac is never invoked per file. Python: no build file; any .py next to another is importable, so this problem does not arise. Rust: Cargo.toml plus 'mod' declarations - a file not reachable from a mod tree is silently not compiled, the closest analogue to forgetting a file in includeFiles. Go: every .go file in a directory is one package, compiled together automatically, closest to applyStandardIncludes. C/C++: the build system lists translation units explicitly, like includeFiles. EK9: packaging is part of the language rather than an external tool - 'defines package' in a .ek9 file IS the build file, and there is no Maven, Gradle or npm to install.
Keywords: files, project, multiple, split, E50001, module, resolved, includeFiles, file, package, build, applyStandardIncludes, source, multifile, structure, directory, sources, sibling, layout, compile, references