Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Autolinking #450

Closed
wants to merge 5 commits into from

2 participants

@galchinsky
  • No explicit clay -lsmth needed to make module work:
clay/test/lang/modules/imports/library$ cat main.clay
import "curl";
external curl_easy_init(): OpaquePointer;
main() {
    curl_easy_init();
}
clay/test/lang/modules/imports/library$ clay main.clay
clay/test/lang/modules/imports/library$ 

Found the idea in Doug Gregor's presentation on slide 67

  • Second commit fixes a bug on my system after upgrade: llvm-jit-linker needs smth.so instead of smth without an extension. I tried to revert to the first patch where linkLibraries appeared, but it has the same error. It didn't have, I don't know why. Please test something like clay -lsmth foo.clay, if it is only my system's trouble or not.
@jckarter
Owner

This is cool. You could also potentially support importing Clang modules directly and automatically generate the necessary external bindings so that clay-bindgen doesn't need to be a separate tool. Instead of creating a new "import" form, what do you think about making it a module attribute, so you'd say in my.module (LinkLibrary["smth"]); ?

@galchinsky

I forgot about module attributes. LinkLibrary["smth"] doesn't work because the analyzer wants to evaluate it and can't find LinkLibrary symbol.
I made an addition to verifyAttibutes so that in my.module (Foo : "smth", Bar : "+zmth", Foo : "blah" ++ "blah", Bar : "-zmth"); will be added to a "multimap"named module::attrParameters (Foo = [smth, blahblah], Bar = [+zmth, -zmth]). I think that it is quite universal.
LinkLibrary entry is passed to linker as it was by `in my.module (LinkLibrary :"smth");

As I can see in clang/test/Modules it is not well implemented yet to support it. Compiler could automatically run bindgen when import .h files. Something like import libc.smth in "smth.h". What do you think?

@jckarter
Owner

You would have to add LinkLibrary as a primitive symbol, similar to RecordWithProperties. But now that you mention it, using keyword pairs makes perfect sense and is a lot cleaner, so I think that's definitely the way to go. I think that it'd also be an improvement to use keywords for external function attributes, since external (asmName:"_foo$BAR") foo() is more descriptive than the current external ("_foo$BAR") foo().

It'd definitely be cool to build bindgen into the compiler as a stopgap until Clang modules mature and start to get used by libraries. I'm not sure what the best design is though, since I don't think you want to duplicate a bunch of common C definitions from common headers into different Clay modules. I had in mind a design in which importing C headers dumped symbols into a __c__ module, and you'd then public import the symbols you wanted to expose through your API module, for instance:

external import "<stdio.h>";
public import __c__.(FILE, fopen, fclose, fread, fwrite);
@galchinsky

What do you mean by "build into"? Bindgen is written in Clay, so it needs the compiler to work. I could call the bindgen through a system(...) in loadDependents. Dynamically linked shared lib is an alternative, but it will be platform dependent.
About the syntax, I think external import "<stdio.h>" as libc.stdio; is more concise than magic __c__ name.

external import "<stdio.h>" as libc.stdio;
extrenal import "<stdlib.h>" as stdlib;
public import  libc.stdio.(FILE, fopen, fclose, fread, fwrite);
public import stdlib.*;
@jckarter
Owner

The bindgen code would have to be rewritten in C++ to embed it in the compiler. Even if the external import form can import symbols into a named module, the symbols have to actually live in a __c__ module or equivalent, because headers need to be able to reference each other's definitions, and you don't want different distinct definitions of things because a header is shared in common with two other headers.

@galchinsky

What is wrong?

$ cat hello.c
int x;
$ cat hello.h
extern int x;
$ cat another.clay
external x : CInt;
$ cat main.clay
import printer.(println);
import another;

external x : CInt;

main(){
   x = 100;
   println(x);
   println(another.x);
}
$ gcc -c hello.c -o hello.o && ar rcs libhello.a hello.o
$ clay main.clay -lhello -L.
/tmp/clayobj-073e64ab.obj: In function `main':
main.clay:(.text+0x16c): undefined reference to `x1'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
@jckarter
Owner
@galchinsky

Fixed the bug with twice-meeted-externals.

I think adding "automatically generate the necessary external bindings" is finished, but it calls clay-bindgen through a pipe. Calling to internal version can be done in makeModuleFromCHeaders in loader.

External ImportMembers and importStar are supported, but importStar will obviously pollute namespace with everything imported:

external "smth.h" import smth;
external "smth2.h" import smth2.*;
//in fact is
import __c__;
import __c__.*;

But anyway I think that things like external "smth.h" import smth(foo, bar); are useful and star import for externals should not be recommended. If anyone wants to use it, he should create new module and public import from it. It should be nicer with clang modules.

Didn't test piping in windows, but MSVS CRT has _popen and _pclose, I don't think there would be a problem.

Also added LibSearchPath module attribute so one can write in main (LinkLibrary : "hello", LibSearchPath : "."); which is passed to clang as -L.

@jckarter
Owner

I'm not a fan of shelling out to bindgen like that. Your other patches look good though.

galchinsky added some commits
@galchinsky galchinsky Autolink libraries. import "smth"; is converted to "-lsmth" command t…
…o linker
a18eb93
@galchinsky galchinsky Add verbose output to linkLibraries
Add '.so' adding to linked library search.
That fixes bug on my machine. Please test a-la: clay -run smthtest.clay -lsmth
e07ef94
@galchinsky galchinsky Add module attribute conversion to Module::attrParameters
in my.module (Foo : "x", Bar : "y") is loaded to Module::attrParameters

LinkLibrary attribute (LinkLibrary : "smth") makes compiler automatically link "smth" library

remove commented function
6b53310
@galchinsky galchinsky Call bindgen from compiler.
In a module all "external imports" are squashed into one __c__ file and passed to clay-bindgen.
Result is converted to invisible module named "__c__modulename.h"

```
external "hello.h" import hello;
in main (LinkLibrary : "hello");
main(){
  hello.hello();
}

```
ccc4587
@galchinsky galchinsky Fix searching bug (by adding module path to searchPaths)
Add LibSearchPath module attributes

fix link error if 'external x' meets more than once
a496e6d
@galchinsky

Me too. It is a scaffold to test the idea and replace with internal bindgen someday, so I tried to localize it. As I said the other "fast" approach is to load bindgen.so with dlopen/loadlibrary, but I don't think that it is much better to move text. Internal bindgen could create AST straightforward (or why else is it needed?) but it'll take a time to rewrite it to C++ and replace println with AST construction.

@galchinsky

I'll close till have enough time to finish

@galchinsky galchinsky closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 2, 2012
  1. @galchinsky
  2. @galchinsky

    Add verbose output to linkLibraries

    galchinsky authored
    Add '.so' adding to linked library search.
    That fixes bug on my machine. Please test a-la: clay -run smthtest.clay -lsmth
  3. @galchinsky

    Add module attribute conversion to Module::attrParameters

    galchinsky authored
    in my.module (Foo : "x", Bar : "y") is loaded to Module::attrParameters
    
    LinkLibrary attribute (LinkLibrary : "smth") makes compiler automatically link "smth" library
    
    remove commented function
  4. @galchinsky

    Call bindgen from compiler.

    galchinsky authored
    In a module all "external imports" are squashed into one __c__ file and passed to clay-bindgen.
    Result is converted to invisible module named "__c__modulename.h"
    
    ```
    external "hello.h" import hello;
    in main (LinkLibrary : "hello");
    main(){
      hello.hello();
    }
    
    ```
  5. @galchinsky

    Fix searching bug (by adding module path to searchPaths)

    galchinsky authored
    Add LibSearchPath module attributes
    
    fix link error if 'external x' meets more than once
This page is out of date. Refresh to see the latest.
View
34 compiler/analyzer.cpp
@@ -1292,6 +1292,40 @@ void verifyAttributes(ModulePtr mod)
mod->attrBuildFlags.push_back(y->str);
break;
}
+ case VALUE_HOLDER: {
+ ValueHolder* vh = (ValueHolder *)obj.ptr();
+ if(vh->type->typeKind == TUPLE_TYPE) {
+ TupleType* t = (TupleType*)vh->type.ptr();
+ if (t->elementTypes.size() < 2) {
+ error(mod->declaration, "Attribute tuple must have one key and at least one value");
+ }
+ StaticType* keyStatic = (StaticType*) t->elementTypes[0].ptr();
+ if (keyStatic->typeKind != STATIC_TYPE) {
+ error(mod->declaration, "Attribute tuple values must be static strings");
+ }
+ Identifier* key = (Identifier*)keyStatic->obj.ptr();
+ if (key->objKind != IDENTIFIER) {
+ error(mod->declaration, "Attribute tuple values must be static strings");
+ }
+ llvm::StringMapEntry<vector<llvm::SmallString<16> > >& v =
+ mod->attrParameters.GetOrCreateValue(key->str);
+ for (int i = 1; i < t->elementTypes.size(); ++i) {
+ StaticType* valueStatic = (StaticType*)t->elementTypes[i].ptr();
+ if (valueStatic->typeKind != STATIC_TYPE) {
+ error(mod->declaration, "Attribute tuple values must be static strings");
+ }
+ Identifier* value = (Identifier*)valueStatic->obj.ptr();
+ if (value->objKind != IDENTIFIER) {
+ error(mod->declaration, "Attribute tuple values must be static strings");
+ }
+ v.getValue().push_back(value->str);
+ }
+ break;
+ }
+ else {
+ //fallthrough
+ }
+ }
default:
string buf;
llvm::raw_string_ostream os(buf);
View
41 compiler/clay.cpp
@@ -140,15 +140,25 @@ static void addOptimizationPasses(llvm::PassManager &passes,
}
}
-static bool linkLibraries(llvm::Module *module, llvm::ArrayRef<string> libSearchPaths, llvm::ArrayRef<string> libs)
+static bool linkLibraries(llvm::Module *module, llvm::ArrayRef<string> libSearchPaths, llvm::ArrayRef<string> libs, bool verbose)
{
if (libs.empty())
return true;
llvm::Linker linker("clay", llvmModule, llvm::Linker::Verbose);
linker.addSystemPaths();
linker.addPaths(libSearchPaths);
+ vector< llvm::sys::Path> a = linker.getLibPaths();
+ if (verbose) {
+ llvm::errs() << "Linking search paths:\n";
+ for (int i = 0; i < a.size(); ++i) {
+ llvm::errs() << a[i].str()<<"\n";
+ }
+ }
for (size_t i = 0; i < libs.size(); ++i){
- string lib = libs[i];
+ string lib = libs[i] + ".so";
+ if (verbose) {
+ llvm::errs() << "Linking " << lib << "...\n";
+ }
llvmModule->addLibrary(lib);
//as in cling/lib/Interpreter/Interpreter.cpp
bool isNative = true;
@@ -177,8 +187,7 @@ static bool linkLibraries(llvm::Module *module, llvm::ArrayRef<string> libSearc
} else if (isNative) {
// native shared library, load it!
llvm::sys::Path SoFile = linker.FindLib(lib);
- if (SoFile.isEmpty())
- {
+ if (SoFile.isEmpty()) {
llvm::errs() << "Couldn't find shared library " << lib << "\n";
linker.releaseModule();
return false;
@@ -204,9 +213,10 @@ static bool runModule(llvm::Module *module,
vector<string> &argv,
char const* const* envp,
llvm::ArrayRef<string> libSearchPaths,
- llvm::ArrayRef<string> libs)
+ llvm::ArrayRef<string> libs,
+ bool verbose)
{
- if (!linkLibraries(module, libSearchPaths, libs)) {
+ if (!linkLibraries(module, libSearchPaths, libs, verbose)) {
return false;
}
llvm::EngineBuilder eb(llvmModule);
@@ -1011,7 +1021,7 @@ int main2(int argc, char **argv, char const* const* envp) {
// Add the relative path from the executable
PathString clayExe(llvm::sys::Path::GetMainExecutable(argv[0], (void *)(uintptr_t)&usage).c_str());
llvm::StringRef clayDir = llvm::sys::path::parent_path(clayExe);
-
+ setClayDir(clayDir);
PathString libDirDevelopment(clayDir);
PathString libDirProduction1(clayDir);
PathString libDirProduction2(clayDir);
@@ -1102,6 +1112,19 @@ int main2(int argc, char **argv, char const* const* envp) {
else
m = loadProgram(clayFile, NULL, verbose, repl);
+ set<string >::const_iterator autolibs = globalLibraries.begin();
+ for (; autolibs != globalLibraries.end(); ++autolibs) {
+ libraries.push_back(*autolibs);
+ librariesArgs.push_back("-l" + *autolibs);
+ }
+
+
+ set<string >::const_iterator libsearchs = globalLinkSearchPath.begin();
+ for (; libsearchs != globalLinkSearchPath.end(); ++libsearchs) {
+ libSearchPath.push_back(*libsearchs);
+ libSearchPathArgs.push_back("-L" + *libsearchs);
+ }
+
loadTimer.stop();
compileTimer.start();
codegenEntryPoints(m, codegenExternals);
@@ -1145,10 +1168,10 @@ int main2(int argc, char **argv, char const* const* envp) {
if (run) {
vector<string> argv;
argv.push_back(clayFile);
- runModule(llvmModule, argv, envp, libSearchPath, libraries);
+ runModule(llvmModule, argv, envp, libSearchPath, libraries, verbose);
}
else if (repl) {
- linkLibraries(llvmModule, libSearchPath, libraries);
+ linkLibraries(llvmModule, libSearchPath, libraries, verbose);
runInteractive(llvmModule, m);
}
else if (emitLLVM || emitAsm || emitObject) {
View
18 compiler/clay.hpp
@@ -348,7 +348,6 @@ public :
}
};
-
//
// ObjectKind
//
@@ -546,6 +545,7 @@ struct Import;
struct ImportModule;
struct ImportStar;
struct ImportMembers;
+struct ImportExternal;
struct Module;
struct ModuleDeclaration;
@@ -699,6 +699,7 @@ typedef Pointer<Import> ImportPtr;
typedef Pointer<ImportModule> ImportModulePtr;
typedef Pointer<ImportStar> ImportStarPtr;
typedef Pointer<ImportMembers> ImportMembersPtr;
+typedef Pointer<ImportExternal> ImportExternalPtr;
typedef Pointer<Module> ModulePtr;
typedef Pointer<ModuleDeclaration> ModuleDeclarationPtr;
@@ -2268,7 +2269,8 @@ struct GlobalAlias : public TopLevelItem {
enum ImportKind {
IMPORT_MODULE,
IMPORT_STAR,
- IMPORT_MEMBERS
+ IMPORT_MEMBERS,
+ IMPORT_EXTERNAL
};
struct Import : public ANode {
@@ -2310,6 +2312,15 @@ struct ImportMembers : public Import {
: Import(IMPORT_MEMBERS, dottedName, visibility) {}
};
+struct ImportExternal : public Import {
+ ImportPtr aggr;
+ llvm::SmallString<16> fileName;
+ ImportExternal(StringLiteralPtr fileName_)
+ : Import(IMPORT_EXTERNAL, NULL, visibility), fileName(fileName) {
+ fileName = fileName_->value->str;
+ }
+};
+
//
// Module
@@ -2373,6 +2384,7 @@ struct Module : public ANode {
EnvPtr env;
InitState initState;
vector<llvm::SmallString<16> > attrBuildFlags;
+ llvm::StringMap<vector<llvm::SmallString<16> > > attrParameters;
IntegerTypePtr attrDefaultIntegerType;
FloatTypePtr attrDefaultFloatType;
@@ -2382,6 +2394,8 @@ struct Module : public ANode {
set<string> importedNames;
+ llvm::SmallString<260u> path;
+
int publicSymbolsLoading:3;
int allSymbolsLoading:3;
bool attributesVerified:1;
View
16 compiler/codegen.cpp
@@ -1503,10 +1503,18 @@ void codegenExternalVariable(ExternalVariablePtr x)
linkage = llvm::GlobalVariable::DLLExportLinkage;
else
linkage = llvm::GlobalVariable::ExternalLinkage;
- x->llGlobal =
- new llvm::GlobalVariable(
- *llvmModule, llvmType(pv.type), false,
- linkage, NULL, x->name->str.str());
+
+ llvm::StringRef name = x->name->str.str();
+ llvm::GlobalVariable* gvar;
+ if (gvar = llvmModule->getGlobalVariable(name)) {
+ x->llGlobal = gvar;
+ } else {
+ x->llGlobal =
+ new llvm::GlobalVariable(
+ *llvmModule, llvmType(pv.type), false,
+ linkage, NULL, name);
+ }
+
if (llvmDIBuilder != NULL) {
int line, column;
llvm::DIFile file = getDebugLineCol(x->location, line, column);
View
148 compiler/loader.cpp
@@ -6,7 +6,7 @@
#include "evaluator.hpp"
#include "constructors.hpp"
#include "parser.hpp"
-
+#include "pipes.hpp"
#pragma clang diagnostic ignored "-Wcovered-switch-default"
@@ -19,8 +19,18 @@ static vector<llvm::SmallString<32> > moduleSuffixes;
llvm::StringMap<ModulePtr> globalModules;
llvm::StringMap<string> globalFlags;
+set<string> globalLibraries;
+set<string> globalLinkSearchPath;
ModulePtr globalMainModule;
+llvm::sys::Path tmpDir;
+
+string clayDir;
+
+void setClayDir(const string& value) {
+ clayDir = value;
+}
+
//
// initModuleSuffixes
@@ -154,14 +164,18 @@ void setSearchPath(llvm::ArrayRef<PathString> path) {
searchPath = path;
}
-static bool locateFile(llvm::StringRef relativePath, PathString &path) {
+static bool locateFile(llvm::StringRef relativePath,
+ PathString &path,
+ bool notClayFile = false) {
// relativePath has no suffix
for (unsigned i = 0; i < searchPath.size(); ++i) {
PathString pathWOSuffix(searchPath[i]);
llvm::sys::path::append(pathWOSuffix, relativePath);
for (unsigned j = 0; j < moduleSuffixes.size(); ++j) {
path = pathWOSuffix;
- path.append(moduleSuffixes[j].begin(), moduleSuffixes[j].end());
+ if (!notClayFile) {
+ path.append(moduleSuffixes[j].begin(), moduleSuffixes[j].end());
+ }
if (llvm::sys::fs::exists(path.str()))
return true;
}
@@ -301,6 +315,96 @@ static void installGlobals(ModulePtr m) {
}
}
+static void makeModuleFromCHeaders(ModulePtr m,
+ vector<string> *sourceFiles,
+ bool verbose) {
+
+ vector<SourcePtr > cFiles;
+ vector<ImportPtr>::iterator ii, iend;
+ iend = m->imports.end();
+ set<llvm::SmallString<16> > headers;
+ searchPath.push_back(llvm::SmallString<260u>(m->path));
+ for (ii = m->imports.begin(); ii != iend; ++ii) {
+ if ((*ii)->importKind == IMPORT_EXTERNAL) {
+ ImportExternal* x = (ImportExternal *)((*ii).ptr());
+ PathString path;
+ if (!locateFile(x->fileName, path, true)) {
+ error("Couldn't locate file " + x->fileName);
+ }
+ if (headers.count(x->fileName) == 0) {
+ cFiles.push_back(new Source(path.str()));
+ headers.insert(x->fileName);
+ }
+ }
+ }
+
+ if (cFiles.size() > 0) {
+ //FIXME: replace bindgen pipe call with internal bingen *
+ string name = "__c__" + m->moduleName + ".h";
+ string nameWithPath = tmpDir.str() + name.c_str();
+ FILE* f = fopen(nameWithPath.c_str(), "w");
+ for (size_t i = 0; i < cFiles.size(); ++i) {
+ fwrite((const void*)cFiles[i]->buffer->getBufferStart(),
+ cFiles[i]->buffer->getBufferSize(), 1, f);
+ }
+ fclose(f);
+
+ string buf;
+ llvm::raw_string_ostream args(buf);
+ args << clayDir << "/../tools/clay-bindgen ";
+ args << "-builtins ";
+ //bug #443
+ //FIXME: shouldn't be need in llvm 3.2
+ args << "-I/usr/include/clang/3.0/include/ ";
+ args << nameWithPath;
+
+ FILE* pipe = popen(args.str().c_str(), "r");
+ if (pipe == NULL) {
+ llvm::errs() << args.str() << "\n";
+ error("Couldn't create clay-bindgen pipe\n");
+ }
+ string buf2;
+ llvm::raw_string_ostream bindgen(buf2);
+ char buf3[256];
+ while(!feof(pipe))
+ {
+ if(fgets(buf3, 256, pipe) != NULL ) {
+ bindgen << buf3;
+ }
+ }
+ pclose(pipe);
+
+ SourcePtr source = new Source(bindgen.str(), 0);
+ //*
+
+ ModulePtr cModule;
+ cModule = parse(name, source, ParserFlags());
+
+ for (ii = m->imports.begin(); ii != iend; ++ii) {
+ //magically replace external header with __c__ module
+ if ((*ii)->importKind == IMPORT_EXTERNAL) {
+ ImportExternalPtr y = (ImportExternal *)ii->ptr();
+ (*ii) = y->aggr.ptr();
+ (*ii)->module = cModule;
+ }
+ }
+
+ llvm::StringMap<ModulePtr>::iterator i = globalModules.find(name);
+ if (i != globalModules.end()) {
+ error(m->location, "module " + name + "already exists");
+ }
+
+ if (verbose) {
+ llvm::errs() << "loading generated module " << name;
+ }
+
+ globalModules[name] = cModule;
+ loadDependents(cModule, sourceFiles, verbose);
+ installGlobals(cModule);
+
+ }
+}
+
static ModulePtr loadModuleByName(DottedNamePtr name, vector<string> *sourceFiles, bool verbose) {
string key = toKey(name);
@@ -323,6 +427,7 @@ static ModulePtr loadModuleByName(DottedNamePtr name, vector<string> *sourceFile
llvm::errs() << "loading module " << name->join() << " from " << path << "\n";
}
module = parse(key, loadFile(path, sourceFiles));
+ module->path = path;
}
globalModules[key] = module;
@@ -332,9 +437,15 @@ static ModulePtr loadModuleByName(DottedNamePtr name, vector<string> *sourceFile
return module;
}
+
void loadDependent(ModulePtr m, vector<string> *sourceFiles, ImportPtr dependent, bool verbose) {
ImportPtr x = dependent;
- x->module = loadModuleByName(x->dottedName, sourceFiles, verbose);
+
+ //is not null when was IMPORT_EXTERNAL
+ if (x->module == NULL) {
+ x->module = loadModuleByName(x->dottedName, sourceFiles, verbose);
+ }
+
switch (x->importKind) {
case IMPORT_MODULE : {
ImportModule *im = (ImportModule *)x.ptr();
@@ -383,15 +494,18 @@ void loadDependent(ModulePtr m, vector<string> *sourceFiles, ImportPtr dependent
y->aliasMap[aliasStr] = z.name;
}
break;
- }
+ }
default :
assert(false);
}
}
static void loadDependents(ModulePtr m, vector<string> *sourceFiles, bool verbose) {
+ makeModuleFromCHeaders(m, sourceFiles, verbose);
+
vector<ImportPtr>::iterator ii, iend;
- for (ii = m->imports.begin(), iend = m->imports.end(); ii != iend; ++ii) {
+ iend = m->imports.end();
+ for (ii = m->imports.begin(); ii != iend; ++ii) {
loadDependent(m, sourceFiles, *ii, verbose);
}
}
@@ -412,7 +526,9 @@ static ModulePtr loadPrelude(vector<string> *sourceFiles, bool verbose, bool rep
}
ModulePtr loadProgram(llvm::StringRef fileName, vector<string> *sourceFiles, bool verbose, bool repl) {
+ tmpDir = llvm::sys::Path::GetTemporaryDirectory();
globalMainModule = parse("", loadFile(fileName, sourceFiles));
+ globalMainModule->path = llvm::sys::path::parent_path(fileName).str();
ModulePtr prelude = loadPrelude(sourceFiles, verbose, repl);
loadDependents(globalMainModule, sourceFiles, verbose);
installGlobals(globalMainModule);
@@ -723,6 +839,26 @@ static void initModule(ModulePtr m, llvm::ArrayRef<string> importChain) {
verifyAttributes(m);
+ llvm::StringMap<vector<llvm::SmallString<16> > >::iterator ii2 = m->attrParameters.begin();
+ llvm::StringMap<vector<llvm::SmallString<16> > >::iterator iend2 = m->attrParameters.end();
+ for (; ii2 != iend2; ++ii2) {
+ if (ii2->getKey() == "LinkLibrary") {
+ vector<llvm::SmallString<16> >& v = ii2->getValue();
+ for (int i = 0; i < v.size(); ++i) {
+ globalLibraries.insert(v[i].str());
+ }
+ } else if (ii2->getKey() == "LibSearchPath") {
+ vector<llvm::SmallString<16> >& v = ii2->getValue();
+ for (int i = 0; i < v.size(); ++i) {
+ PathString p(m->path.str());
+ if (llvm::sys::path::is_relative(p + "")) {
+ llvm::sys::path::append(p, v[i].str());
+ }
+ globalLinkSearchPath.insert(p.str());
+ }
+ }
+ }
+
llvm::ArrayRef<TopLevelItemPtr> items = m->topLevelItems;
TopLevelItemPtr const *ti, *tend;
for (ti = items.begin(), tend = items.end(); ti != tend; ++ti) {
View
4 compiler/loader.hpp
@@ -8,8 +8,12 @@ namespace clay {
extern llvm::StringMap<ModulePtr> globalModules;
extern llvm::StringMap<string> globalFlags;
+extern set<string> globalLibraries;
+extern set<string> globalLinkSearchPath;
extern ModulePtr globalMainModule;
+extern void setClayDir(const string& value);
+
void addProcedureOverload(ProcedurePtr proc, EnvPtr Env, OverloadPtr x);
void getProcedureMonoTypes(ProcedureMono &mono, EnvPtr env,
llvm::ArrayRef<FormalArgPtr> formalArgs, bool hasVarArg);
View
50 compiler/parser.cpp
@@ -2886,6 +2886,20 @@ static bool importMembers(ImportPtr &x) {
return true;
}
+/*static bool importExternal(ImportPtr &x) {
+ Location location = currentLocation();
+ Visibility vis;
+ if (!importVisibility(vis)) return false;
+ if (!keyword("external")) return false;
+ if (!keyword("import")) return false;
+ ExprPtr fileName;
+ if (!stringLiteral(fileName)) return false;
+ if (!symbol(";")) return false;
+ x = z.ptr();
+ x->location = location;
+ return true;
+}*/
+
static bool import(ImportPtr &x) {
int p = save();
if (importModule(x)) return true;
@@ -2894,12 +2908,46 @@ static bool import(ImportPtr &x) {
return false;
}
+static bool optExternalImport() {
+ int p = save();
+ if (keyword("external")) {
+ return true;
+ } else {
+ restore(p);
+ return false;
+ }
+}
+
+static bool importInternalOrExternal(ImportPtr &x) {
+ bool external = false;
+ ImportExternalPtr e;
+
+ if (optExternalImport()) {
+ external = true;
+ ExprPtr fileName;
+ if (!stringLiteral(fileName)) return false;
+ e = new ImportExternal((StringLiteral*) fileName.ptr());
+ }
+
+ ImportPtr y;
+ if (!import(y)) return false;
+
+ if (external) {
+ e->aggr = y;
+ x = e.ptr();
+ } else {
+ x = y;
+ }
+
+ return true;
+}
+
static bool imports(vector<ImportPtr> &x) {
x.clear();
while (true) {
int p = save();
ImportPtr y;
- if (!import(y)) {
+ if (!importInternalOrExternal(y)) {
restore(p);
break;
}
View
12 compiler/pipes.hpp
@@ -0,0 +1,12 @@
+#ifndef __PIPES_HPP
+#define __PIPES_HPP
+
+#ifdef _MSC_VER
+ #include <stdlib.h>
+ #define popen _popen
+ #define pclose _pclose
+#else
+ #include <unistd.h>
+#endif
+
+#endif
View
5 test/lang/modules/imports/external/another.clay
@@ -0,0 +1,5 @@
+external "hello.h" import hello;
+
+say(){
+ hello.sayX();
+}
View
21 test/lang/modules/imports/external/hello.c
@@ -0,0 +1,21 @@
+#include "hello.h"
+
+#include "hello2.h"
+
+int x;
+
+void setX(int value) {
+ x = value;
+}
+
+int getX() {
+ return x;
+}
+
+void sayX() {
+ printf("%d\n", x);
+}
+
+void sayDoubleX() {
+ printf("%d\n", x * 2);
+}
View
7 test/lang/modules/imports/external/hello.h
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+extern int x;
+
+void setX(int value);
+int getX();
+void sayX();
View
4 test/lang/modules/imports/external/hello2.h
@@ -0,0 +1,4 @@
+#include <stdio.h>
+
+void sayDoubleX();
+
View
BIN  test/lang/modules/imports/external/libhello.a
Binary file not shown
View
15 test/lang/modules/imports/external/main.clay
@@ -0,0 +1,15 @@
+import another;
+external "hello.h" import hello;
+external "hello.h" import hello.(setX, sayX, getX);
+//in fact star pollutes namespace with all __c__ module
+external "hello2.h" import hello1;
+external "hello2.h" import hello1.*;
+
+in main (LinkLibrary : "hello", LibSearchPath : ".");
+
+main() {
+ hello.setX(50);
+ hello.sayX();//50
+ another.say();
+ hello1.sayDoubleX();
+}
View
3  test/lang/modules/imports/external/out.txt
@@ -0,0 +1,3 @@
+50
+50
+100
View
7 test/lang/modules/imports/library/main.clay
@@ -0,0 +1,7 @@
+in main (LinkLibrary: "curl");
+
+external curl_easy_init(): OpaquePointer;
+
+main() {
+ curl_easy_init();
+}
View
0  test/lang/modules/imports/library/out.txt
No changes.
Something went wrong with that request. Please try again.