Browse Source

Refactored importing

* Changed include to import (for Cakelisp files) and c-import
  instead. I threw away the simple include function because I decided
  using a conventional build system to parse the includes was
  unfeasible
* Added &comptime-only to resolve cases where macro- and
  generator-only files don't actually create any headers, but are
  still useful to import
* Made proper runtime build and run command
* Add CommandLineOptions.cake to feel out advanced struct annotation
HotReloadingState
Macoy Madson 5 months ago
parent
commit
da949f0f8d
18 changed files with 311 additions and 162 deletions
  1. +3
    -1
      BuildAndRunTests.sh
  2. +39
    -5
      doc/Cakelisp.org
  3. +2
    -4
      runtime/HotReloading.cake
  4. +10
    -0
      runtime/Jamfile
  5. +102
    -0
      runtime/Jamrules
  6. +6
    -0
      runtime/TestMain.cake
  7. +14
    -2
      src/FileUtilities.cpp
  8. +1
    -0
      src/FileUtilities.hpp
  9. +70
    -134
      src/Generators.cpp
  10. +5
    -3
      src/ModuleManager.cpp
  11. +2
    -3
      test/Basic.cake
  12. +3
    -3
      test/BuildWithJam/Main.cake
  13. +2
    -2
      test/BuildWithJam/TestCakeDependency.cake
  14. +47
    -0
      test/CommandLineOptions.cake
  15. +2
    -2
      test/Dependencies.cake
  16. +1
    -1
      test/DependenciesModule.cake
  17. +1
    -1
      test/Hello.cake
  18. +1
    -1
      test/Test.cake

+ 3
- 1
BuildAndRunTests.sh View File

@ -3,4 +3,6 @@
# jam -j4 && ./bin/cakelisp test/Macros.cake
# jam -j4 && ./bin/cakelisp test/Dependencies.cake
# jam -j4 && ./bin/cakelisp test/Basic.cake
jam -j4 && ./bin/cakelisp runtime/HotReloading.cake
# Build Cakelisp itself, generate the runtime, build the runtime, then run the test
jam -j4 && ./bin/cakelisp runtime/TestMain.cake && cd runtime && jam -j4 && ./HotReloadingTest

+ 39
- 5
doc/Cakelisp.org View File

@ -24,18 +24,52 @@ Modules serve as a powerful organization mechanism. It's easy to see how a proje
Modules automatically provide both the interface and implementation files necessary. This means appropriate ~.h~ or ~.hpp~ header files are generated for the given generated ~.c~ or ~.cpp~ file.
The ~local~ keyword or suffix is typically relative to module scope. It tells Cakelisp that this function/variable/struct definition/etc. is not intended to be used outside the current module. Declaring module-local variables is a particularly clean way to let modules manage their own memory, without having to pass the module's data around to all its functions and all its callers. See /Code Complete/, 1st Edition, p. 128 "Module data mistaken for global data".
* Includes
** Importing modules
The ~import~ function adds the specified file to the environment:
#+BEGIN_SRC lisp
(import "MyFile.cake" "AnotherFile.cake")
;; Include MyForwardDeclares.cake's generated header in the current module's generated header
;; You might need to do this if you have non-module-local types/signatures which rely on other types
(import &with-decls "MyForwardDeclares.cake")
;; Do not include in any generated code. This is essential for comptime-only modules, which won't
;; even generate headers
(import &comptime-only "Macros.cake")
#+END_SRC
By default, ~&with-defs~ is specified, meaning the generated header will be included in the generated source file only.
Files are evaluated the instant they are imported. If a file has already imported, it will not be evaluated again.
Circular imports are allowed because C/C++ generated headers will make it possible to build the generated code. Circular references are not allowed in macros or generators, because they cannot be built without having built the other.
* C/C++ Imports
Thanks to speculative compilation, *any* C or C++ header may be included in Cakelisp files, and the header's functions and types may be used freely. This is in stark contrast to many other languages which require bindings, FFIs, etc. in order to call C code. It works just as well as a native C file. This eliminates any additional work needed to integrate C/C++ libraries. It also means there is no need to create a Cakelisp standard library, because you already have easy access to the entire C and C++ standard libraries!
This also means that adding Cakelisp to an existing C/C++ project should be virtually effortless. All of your existing code is ready to be used. Additionally, Cakelisp code compiles down to regular C/C++ code, so calling a Cakelisp function is as easy as calling a native C/C++ function. There's no boxing/unboxing, marshalling, type conversions, etc. necessary.
Here are some example includes:
Here are some example imports:
#+BEGIN_SRC lisp
(include "<vector>") ;; now just e.g. (var my-vec (<> std::vector int) (array 1 2 3))
(include "<cstdio.h>") ;; (printf "Hello %s!\n" "Cakelisp")
(include "MyHeader.hpp") ;; (on-call myGlobalVar updateState 0.016)
(c-import "<vector>") ;; now just e.g. (var my-vec (<> std::vector int) (array 1 2 3))
(c-import "<cstdio.h>") ;; (printf "Hello %s!\n" "Cakelisp")
(c-import "MyHeader.hpp") ;; (on-call myGlobalVar updateState 0.016)
;; Multiple imports are allowed per call:
(c-import "<vector>" "<map>")
#+END_SRC
The destination of imports may be specified:
#+BEGIN_SRC lisp
(c-import &with-decls "<vector>") ;; Make sure the header file (declarations) includes vector
;; Go back and forth between destinations freely:
(c-import &with-decls "toHeader.hpp" "anotherHeaderHeader.hpp"
&with-defs "toSource.cpp")
#+END_SRC
By default, ~&with-defs~ is specified.
You shouldn't expect Cakelisp features to work with external C/C++ code. Features like hot-reloading or introspection aren't available to external code because Cakelisp does not parse any C/C++ headers. This doesn't mean you cannot call C/C++ code from a hot-reloaded Cakelisp function, it just means you cannot magically hot-reload the C/C++ code you're calling.
* Functions
Functions are defined with ~defun~. ~defun~ provides some variants via different invocations:


+ 2
- 4
runtime/HotReloading.cake View File

@ -1,7 +1,5 @@
(include "Macros.cake")
(include "<unordered_map>")
(include "<vector>")
(import &comptime-only "Macros.cake")
(c-import "<unordered_map>" "<vector>")
;; The first significant generator written in Cakelisp!
(defgenerator def-type-alias ()


+ 10
- 0
runtime/Jamfile View File

@ -0,0 +1,10 @@
# Cannot build from root because our files won't exist yet, and cakelisp needs to be built first.
# This could be fixed via a custom dependency which would wait for Cakelisp to be built, then
# generate our files. HotReloadingTest would also have a dependency on that. However, even this
# might not work because Jam might need to process the includes right away, and the files still
# don't exist. So, it's complicated, but doing the easy way is fine and doesn't bother me too much
SubDir . ;
Main HotReloadingTest : TestMain.cake.cpp
HotReloading.cake.cpp
;

+ 102
- 0
runtime/Jamrules View File

@ -0,0 +1,102 @@
##
## Compilation
##
C++ = clang++ ;
LINK = clang++ ;
# C++ = g++ ;
# LINK = g++ ;
if $(UNIX) { SUFSHR = .so ; }
else if $(NT) { SUFSHR = .dll ; }
if $(CROSS_COMPILE_WINDOWS)
{
C++ = x86_64-w64-mingw32-g++ ;
LINK = x86_64-w64-mingw32-g++ ;
AR = x86_64-w64-mingw32-ar ;
SUFEXE = .exe ;
OS_DEPENDENT_C++FLAGS = -DWINDOWS ;
OS_DEPENDENT_LINKLIBS = ;
OS_DEPENDENT_LINKFLAGS = --export-all-symbols ;
MINGW_LIB_PATH = /usr/lib/gcc/x86_64-w64-mingw32/7.3-win32 ;
OS_DEPENDENT_DLLS =
$(MINGW_LIB_PATH)/libgcc_s_seh-1.dll
$(MINGW_LIB_PATH)/libstdc++-6.dll ;
}
else if $(UNIX)
{
OS_DEPENDENT_C++FLAGS = -DUNIX ;
# For dynamic loading: ldl loads, export-dynamic lets the loaded code resolve its symbols to the loader's code
OS_DEPENDENT_LINKLIBS = -ldl ;
OS_DEPENDENT_LINKFLAGS = --export-dynamic ;
OS_DEPENDENT_DLLS = ;
}
else if $(NT)
{
OS_DEPENDENT_C++FLAGS = -DWINDOWS ;
# TODO: Windows support
OS_DEPENDENT_LINKLIBS = ;
OS_DEPENDENT_LINKFLAGS = ;
OS_DEPENDENT_DLLS = ;
}
# Arguments used on all projects, regardless of any variables
C++FLAGS = -std=c++11 -Wall -Wextra -Wno-unused-parameter
# Only for profiling, i.e. not release builds
# -DTRACY_ENABLE
-g
# Needed for dynamic linking
-fPIC
$(OS_DEPENDENT_C++FLAGS)
;
# TODO: Make base hold all this weirdness?
# if $(DEBUG_BUILD)
# {
# SFML_LINKLIBS = -lsfml-audio-d -lsfml-graphics-d -lsfml-window-d -lsfml-system-d ;
# }
# else
# {
# SFML_LINKLIBS = -lsfml-audio -lsfml-graphics -lsfml-window -lsfml-system ;
# }
OPTIM = -O0 ;
##
## Linking
##
LINKLIBS =
# Standard (e.g. for Tracy)
-lpthread
# Functions for dynamically loading libraries (UNIX)
$(OS_DEPENDENT_LINKLIBS)
;
LINKFLAGS = -g
# -Wl = pass to linker
# --export-dynamic = Export all symbols so dynamically loaded code can resolve their symbols to ours
-Wl,-rpath,.,$(OS_DEPENDENT_LINKFLAGS)
;
##
## Jam stuff
##
# Fix for unnecessary rebuilding any Jam project
KEEPOBJS = true ; # This doesn't actually fix anything, though it seems like it should
NOARSCAN = true ; # This actually fixes the problem
#AR = ar rUu ; # I was thinking maybe the AR command was wrong (always outputting deterministically)
# It doesn't seem like this is the problem though
AR = ar cr ;
# Some helpful Jam commands
# -q : stop on failed target
# -jN : use N cores
# -sVAR=VAL : Set VAR to VAL. Note that setting WINDOWS=false is the same as setting WINDOWS=true,
# frustratingly (as if it's an ifdef not an if x = y
# -dx : print commands being used
# -n : don't actually run commands

+ 6
- 0
runtime/TestMain.cake View File

@ -0,0 +1,6 @@
(import "HotReloading.cake")
(c-import "stdio.h")
(defun main (&return int)
(printf "Hello Hot-reloading!\n")
(return 0))

+ 14
- 2
src/FileUtilities.cpp View File

@ -6,8 +6,8 @@
#include <string.h>
#ifdef UNIX
#include <sys/stat.h>
#include <libgen.h>
#include <sys/stat.h>
#else
#error Need to implement file utilities for this platform
#endif
@ -54,6 +54,18 @@ void getDirectoryFromPath(const char* path, char* bufferOut, int bufferSize)
SafeSnprinf(bufferOut, bufferSize, "%s", dirName);
free(pathCopy);
#else
#error Need to be able to strip file from path to get directory
#error Need to be able to strip file from path to get directory on this platform
#endif
}
void getFilenameFromPath(const char* path, char* bufferOut, int bufferSize)
{
#ifdef UNIX
char* pathCopy = strdup(path);
const char* fileName = basename(pathCopy);
SafeSnprinf(bufferOut, bufferSize, "%s", fileName);
free(pathCopy);
#else
#error Need to be able to strip path to get filename on this platform
#endif
}

+ 1
- 0
src/FileUtilities.hpp View File

@ -8,3 +8,4 @@ bool fileIsMoreRecentlyModified(const char* filename, const char* reference);
void makeDirectory(const char* path);
void getDirectoryFromPath(const char* path, char* bufferOut, int bufferSize);
void getFilenameFromPath(const char* path, char* bufferOut, int bufferSize);

+ 70
- 134
src/Generators.cpp View File

@ -9,33 +9,34 @@
#include <string.h>
enum CImportState
enum ImportState
{
WithDefinitions,
WithDeclarations
WithDeclarations,
CompTimeOnly
};
// These need to be simple in order to make it easy for external build tools to parse them
// This version supports multiple includes per invocation, different export destinations, etc.
bool PowerfulCImportGenerator(EvaluatorEnvironment& environment, const EvaluatorContext& context,
const std::vector<Token>& tokens, int startTokenIndex,
GeneratorOutput& output)
bool ImportGenerator(EvaluatorEnvironment& environment, const EvaluatorContext& context,
const std::vector<Token>& tokens, int startTokenIndex, GeneratorOutput& output)
{
if (!ExpectEvaluatorScope("C/C++ include", tokens[startTokenIndex], context,
EvaluatorScope_Module))
if (!ExpectEvaluatorScope("import", tokens[startTokenIndex], context, EvaluatorScope_Module))
return false;
int endTokenIndex = FindCloseParenTokenIndex(tokens, startTokenIndex);
// Generators receive the entire invocation. We'll ignore it in this case
StripInvocation(startTokenIndex, endTokenIndex);
if (!ExpectInInvocation("expected path(s) to include", tokens, startTokenIndex,
endTokenIndex + 1))
int startNameTokenIndex = startTokenIndex;
int endArgsIndex = endTokenIndex;
StripInvocation(startNameTokenIndex, endArgsIndex);
if (!ExpectInInvocation("expected path(s) to modules to import", tokens, startNameTokenIndex,
endTokenIndex))
return false;
CImportState state = WithDefinitions;
// C/C++ imports are "c-import"
bool isCakeImport = tokens[startTokenIndex + 1].contents.compare("import") == 0;
ImportState state = WithDefinitions;
// No macros/tomfoolery allowed - these need to be easy to parse by external tools
for (int i = startTokenIndex; i <= endTokenIndex; ++i)
for (int i = startNameTokenIndex; i <= endArgsIndex; ++i)
{
const Token& currentToken = tokens[i];
@ -45,6 +46,15 @@ bool PowerfulCImportGenerator(EvaluatorEnvironment& environment, const Evaluator
state = WithDefinitions;
else if (currentToken.contents.compare("&with-decls") == 0)
state = WithDeclarations;
else if (currentToken.contents.compare("&comptime-only") == 0)
{
if (!isCakeImport)
{
ErrorAtToken(currentToken, "&comptime-only not supported on C/C++ imports");
return false;
}
state = CompTimeOnly;
}
else
{
ErrorAtToken(currentToken, "Unrecognized sentinel symbol");
@ -53,148 +63,73 @@ bool PowerfulCImportGenerator(EvaluatorEnvironment& environment, const Evaluator
continue;
}
else if (!ExpectTokenType("C/C++ include", currentToken, TokenType_String) ||
else if (!ExpectTokenType("import file", currentToken, TokenType_String) ||
currentToken.contents.empty())
continue;
// TODO: Convert to StringOutputs?
char includeBuffer[MAX_PATH_LENGTH] = {0};
// #include <stdio.h> is passed in as "<stdio.h>", so we need a special case (no quotes)
if (currentToken.contents[0] == '<')
{
PrintfBuffer(includeBuffer, "#include %s", currentToken.contents.c_str());
}
else
{
PrintfBuffer(includeBuffer, "#include \"%s\"", currentToken.contents.c_str());
}
if (state == WithDefinitions)
addStringOutput(output.source, std::string(includeBuffer), StringOutMod_NewlineAfter,
&currentToken);
else if (state == WithDeclarations)
addStringOutput(output.header, std::string(includeBuffer), StringOutMod_NewlineAfter,
&currentToken);
output.imports.push_back({currentToken.contents, ImportLanguage_C, &currentToken});
}
return true;
}
// The hampered version of PowerfulCImportGenerator, done so for easy external tool parsing
// No macros/tomfoolery allowed - these need to be easy to parse by external tools
bool CIncludeGenerator(EvaluatorEnvironment& environment, const EvaluatorContext& context,
const std::vector<Token>& tokens, int startTokenIndex,
GeneratorOutput& output)
{
if (!ExpectEvaluatorScope("C/C++ include", tokens[startTokenIndex], context,
EvaluatorScope_Module))
return false;
CImportState state = WithDefinitions;
int endInvocationIndex = FindCloseParenTokenIndex(tokens, startTokenIndex);
int startArgsIndex = startTokenIndex;
int endArgsIndex = endInvocationIndex;
// Generators receive the entire invocation. We'll ignore it in this case
StripInvocation(startArgsIndex, endArgsIndex);
if (!ExpectInInvocation("expected path to include", tokens, startArgsIndex, endArgsIndex + 1))
return false;
const Token& pathToken = tokens[startArgsIndex];
if (!ExpectTokenType("C/C++ include", pathToken, TokenType_String) ||
pathToken.contents.empty())
return false;
int destinationIndex = startArgsIndex + 1;
if (destinationIndex != endInvocationIndex)
{
const Token& destinationToken = tokens[destinationIndex];
if (destinationToken.type == TokenType_Symbol && isSpecialSymbol(destinationToken))
{
if (destinationToken.contents.compare(":with-defs") == 0)
state = WithDefinitions;
else if (destinationToken.contents.compare(":with-decls") == 0)
state = WithDeclarations;
else
{
ErrorAtToken(destinationToken,
"unrecognized sentinel symbol. Expected :with-defs or :with-decls");
return false;
}
}
else
{
ErrorAtToken(destinationToken, "unexpected symbol. Expected :with-defs or :with-decls");
return false;
}
}
bool isCakeImport = false;
// TODO: Convert to StringOutputs?
char includeBuffer[MAX_PATH_LENGTH] = {0};
// #include <stdio.h> is passed in as "<stdio.h>", so we need a special case (no quotes)
if (pathToken.contents[0] == '<')
{
PrintfBuffer(includeBuffer, "#include %s", pathToken.contents.c_str());
}
else
{
// Anything ending with .cake is a Cakelisp include
// It is necessary to have both Cakelisp and C/C++ includes share the same keyword so some
// build systems can handle them (though those build systems need to check for .cake too)
int pathLength = pathToken.contents.size();
const std::string cakeSuffix = ".cake";
if (pathToken.contents.substr(pathLength - cakeSuffix.size(), pathLength)
.compare(cakeSuffix) == 0)
if (isCakeImport)
{
isCakeImport = true;
// TODO Only include the cakelisp file if it is actually needed. For example, macro-only
// .cake files will not have a header output at all
// TODO Make .hpp optional for C-only support
PrintfBuffer(includeBuffer, "#include \"%s.hpp\"", pathToken.contents.c_str());
if (!environment.moduleManager)
{
ErrorAtToken(pathToken,
ErrorAtToken(currentToken,
"importing Cakelisp modules is disabled in this environment");
return false;
}
else
{
char relativePathBuffer[MAX_PATH_LENGTH] = {0};
getDirectoryFromPath(pathToken.source, relativePathBuffer,
getDirectoryFromPath(currentToken.source, relativePathBuffer,
sizeof(relativePathBuffer));
strcat(relativePathBuffer, "/");
strcat(relativePathBuffer, pathToken.contents.c_str());
strcat(relativePathBuffer, currentToken.contents.c_str());
// Evaluate the import!
if (!moduleManagerAddEvaluateFile(*environment.moduleManager,
relativePathBuffer))
if (!moduleManagerAddEvaluateFile(*environment.moduleManager, relativePathBuffer))
{
ErrorAtToken(pathToken, "failed to import Cakelisp module");
ErrorAtToken(currentToken, "failed to import Cakelisp module");
return false;
}
}
}
else
// Comptime only means no includes in the generated file
if (state != CompTimeOnly)
{
PrintfBuffer(includeBuffer, "#include \"%s\"", pathToken.contents.c_str());
}
}
std::vector<StringOutput>& outputDestination =
state == WithDefinitions ? output.source : output.header;
addStringOutput(outputDestination, "#include", StringOutMod_SpaceAfter, &currentToken);
// #include <stdio.h> is passed in as "<stdio.h>", so we need a special case (no quotes)
if (currentToken.contents[0] == '<')
{
addStringOutput(outputDestination, currentToken.contents, StringOutMod_None,
&currentToken);
}
else
{
if (isCakeImport)
{
char cakelispExtensionBuffer[MAX_PATH_LENGTH] = {0};
// TODO: .h vs. .hpp
PrintfBuffer(cakelispExtensionBuffer, "%s.hpp", currentToken.contents.c_str());
addStringOutput(outputDestination, cakelispExtensionBuffer,
StringOutMod_SurroundWithQuotes, &currentToken);
}
else
{
addStringOutput(outputDestination, currentToken.contents,
StringOutMod_SurroundWithQuotes, &currentToken);
}
}
if (state == WithDefinitions)
addStringOutput(output.source, std::string(includeBuffer), StringOutMod_NewlineAfter,
&pathToken);
else if (state == WithDeclarations)
addStringOutput(output.header, std::string(includeBuffer), StringOutMod_NewlineAfter,
&pathToken);
addLangTokenOutput(outputDestination, StringOutMod_NewlineAfter, &currentToken);
}
output.imports.push_back({pathToken.contents,
isCakeImport ? ImportLanguage_Cakelisp : ImportLanguage_C,
&pathToken});
output.imports.push_back({currentToken.contents,
isCakeImport ? ImportLanguage_Cakelisp : ImportLanguage_C,
&currentToken});
}
return true;
}
@ -1681,7 +1616,8 @@ void importFundamentalGenerators(EvaluatorEnvironment& environment)
// I wanted to use c-import, but I encountered problems writing a regex for Jam which can
// handle both include and c-import. Anyways, this way C programmers have one less change to
// remember
environment.generators["include"] = CIncludeGenerator;
environment.generators["c-import"] = ImportGenerator;
environment.generators["import"] = ImportGenerator;
environment.generators["defun"] = DefunGenerator;
environment.generators["defun-local"] = DefunGenerator;


+ 5
- 3
src/ModuleManager.cpp View File

@ -196,10 +196,12 @@ bool moduleManagerWriteGeneratedOutput(ModuleManager& manager)
WriterOutputSettings outputSettings;
outputSettings.sourceCakelispFilename = module.filename.c_str();
char sourceHeadingBuffer[1024] = {0};
// TODO: hpp to h support
// TODO: Strip path from filename
PrintfBuffer(sourceHeadingBuffer, "#include \"%s.hpp\"\n%s", module.filename.c_str(),
char relativeIncludeBuffer[MAX_PATH_LENGTH];
getFilenameFromPath(module.filename.c_str(), relativeIncludeBuffer,
sizeof(relativeIncludeBuffer));
char sourceHeadingBuffer[1024] = {0};
PrintfBuffer(sourceHeadingBuffer, "#include \"%s.hpp\"\n%s", relativeIncludeBuffer,
generatedSourceHeading ? generatedSourceHeading : "");
outputSettings.sourceHeading = sourceHeadingBuffer;
outputSettings.sourceFooter = generatedSourceFooter;


+ 2
- 3
test/Basic.cake View File

@ -1,9 +1,8 @@
;; Quite possibly the simplest generator: slap "#include {arg}" into the source file
;; These need to be simple in order to make it easy for external build tools to parse them
;; Otherwise, they'd support multiple includes per invocation, etc.
(include "<stdio.h>")
(include "<vector>" :with-decls)
;; (include "Test.cake")
(c-import "<stdio.h>" &with-decls "<vector>")
;; (import "Test.cake")
(var my-module-var int 5)


+ 3
- 3
test/BuildWithJam/Main.cake View File

@ -1,6 +1,6 @@
(include "<stdio.h>")
(include "TestHeader.hpp")
(include "TestCakeDependency.cake")
(c-import "<stdio.h>")
(c-import "TestHeader.hpp")
(import "TestCakeDependency.cake")
(defun main (&return int)
(printf "Hello from Cakelisp! My message: %s\nThe answer is %d\n" MY_MESSAGE (the-answer))


+ 2
- 2
test/BuildWithJam/TestCakeDependency.cake View File

@ -1,5 +1,5 @@
(include "DepOfDep.hpp")
(include "<stdio.h>")
(c-import "DepOfDep.hpp")
(c-import "<stdio.h>")
(defun the-answer (&return int)
(printf "\nCalculating...\n")


+ 47
- 0
test/CommandLineOptions.cake View File

@ -0,0 +1,47 @@
;; This serves as a possible way to handle arguments. It won't actually generate
(defenum language-policy
only-c
assume-c++
mixed-c-c++)
(defenum cakelisp-operation
build
clean
;; Go from generated source to Cakelisp file/line number, and vise versa
map)
(defenum name-policy
pascal-case-if-plural
camel-case
underscores)
(defstruct cakelisp-build-options
files :required :help "The .cake files to build. These files' imports will automatically be added"
policy language-policy
name-translation-format name-policy
:help "How to format symbol names when converting lisp-style-names to c_style_names (example is underscores mode)"
working-directory (* (const char)) :help "Where to keep cached artifacts for partial builds"
include-directories (* (* (const char))) :help "Where to search for .cake files"
;; Compile-time options
compile-executable (* (const char)) :help "Path to a C++ compiler (for compile time code)"
compile-options (* (* (const char))) :help "Use {file} to denote the .cpp file being compiled (for compile time code)"
link-executable (* (const char))
:help "Path to an executable capable of linking object (.o) files into dynamic libraries (for compile time code)"
link-options (* (* (const char))) :help "Use {file} to denote the .o file being linked (for compile time code)"
;; Debugging
verbose-files bool
verbose-build bool
verbose-references bool)
(defstruct cakelisp-map-options
"Find the associated source tokens of the given generated file character position, or vice versa"
filename (* (const char)) :required
line int :help "Required if char-position is not provided"
column int :help "Required if char-position is not provided"
char-position int
:help "The index into the array of all characters in the file. This matches e.g. Emacs' goto-char. Starts at 1")

+ 2
- 2
test/Dependencies.cake View File

@ -1,5 +1,5 @@
(include "<stdio.h>")
(include "DependenciesModule.cake")
(c-import "<stdio.h>")
(import "DependenciesModule.cake")
(defun main (&return int)
(printf "%s\n" (hello-from-comptime))


+ 1
- 1
test/DependenciesModule.cake View File

@ -1,5 +1,5 @@
;; This doesn't cause problems thanks to already loaded checks
(include "Dependencies.cake")
(import "Dependencies.cake")
(defmacro empty-macro ()
(return true))

+ 1
- 1
test/Hello.cake View File

@ -1,4 +1,4 @@
(include "<stdio.h>")
(c-import "<stdio.h>")
(defun main(&return int)
(printf "Hello, world! From Cakelisp!\n")


+ 1
- 1
test/Test.cake View File

@ -1,4 +1,4 @@
(include "<stdio.h>")
(c-import "<stdio.h>")
; This is a file to test the tokenizer
(printf "This is a test 0")
;(printf "This is a test 1")


Loading…
Cancel
Save