Examples of integrating C and ATS

178 views
Skip to first unread message

Brandon Barker

unread,
Jun 21, 2018, 10:16:55 PM6/21/18
to ats-lang-users
Hello,

I apologize or being rather unprepared in this question, but this week I've had little time to look into it after thinking about it in the weekend and getting the nix build environment working (which honestly, wasn't much work, and could've been less if I knew then what I know now). I'll be traveling for over a week with limited connectivity wanted to have some examples ready to go, just in case I have some time to read/tinker at the end of the day while away.

If folks know of any good examples where C code and ATS are mingled, that would be great. I hope to gradually port a mid sized C project to ATS; the project uses the classic autotools and GNU make build system.

Thanks!

Chris Double

unread,
Jun 21, 2018, 11:01:42 PM6/21/18
to ats-lan...@googlegroups.com
On Fri, Jun 22, 2018 at 2:16 PM, Brandon Barker
<brandon...@gmail.com> wrote:
> Hello,
>
> If folks know of any good examples where C code and ATS are mingled, that
> would be great. I hope to gradually port a mid sized C project to ATS; the
> project uses the classic autotools and GNU make build system.

See the ats_safe and ats branches of: https://github.com/doublec/openssl

It shows porting parts of openssl into ATS as described here
https://bluishcoder.co.nz/2014/04/11/preventing-heartbleed-bugs-with-safe-languages.html

--
http://bluishcoder.co.nz

Brandon Barker

unread,
Jun 21, 2018, 11:12:56 PM6/21/18
to ats-lang-users
Great, I remember this now, thanks! Saved to Pocket, including GitHub diffs, which look surprisingly good in Pocket (a Mozilla product I believe!)

--
You received this message because you are subscribed to a topic in the Google Groups "ats-lang-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/ats-lang-users/DjbmPoC6mjM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.
Visit this group at https://groups.google.com/group/ats-lang-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/ats-lang-users/CALn1vHGkJhD_m6YzVKDwLfOPKGjgyOo%3DLLTRPAP%2BBRi_DMJbEw%40mail.gmail.com.

Julian Fondren

unread,
Jun 22, 2018, 12:15:45 AM6/22/18
to ats-lang-users
Hi.

It'll help of course to know autotools and GNU make. I only dimly remember the former...

Introduction to Programming in ATS has a whole section on C that has most of what you need: http://www.ats-lang.org/Documents.html#INT2PROGINATS

Then you just compile C and ATS both to object .o files and then link them together. C names in the object are as they appear in the source; ATS names are heavily mangled in order to prevent collisions, by default actually including the compile-time location of the source file in the symbols produced. The doc above tells you how to tell ATS to use C symbols, and also how to give specific symbol names to ATS functions to that C can call them.

So for example, if your C program includes a dict.c that implements a hash table and then a simple interface to remember and recall some definitions,

void remember_this(char *name, char *meaning);
char *what_was(char *name); /* returns meaning */

then you can delete that file with prejudice, write dict.ats, use ATS's provided hash tables, and include:

extern fun remember_this: (string, string) -> void = "ext#"
extern fun what_was: string -> string = "ext#"

implement remember_this
(k, v) = ...

then link that with the rest of the program and, voila, it should work just the same as before. Bit by bit, flesh becomes Borg! Or however you'd like to think of it.

Note that dynamic operations outside of functions, such as

val fruits = $list{string}("apples", "pears", "tomatoes (yes really)")
val
() = println!("the previous line builds the list at runtime!")

are compiled into their own function that gets called prior to main() - in an ATS-initiated program. If a C main() is starting your program, that function won't get called unless you trouble yourself to call it. And there's one per .dats file has any such operations (where ATS_DYNLOADFLAG isn't set to 0, I believe). Since your goal is to rewrite the whole program to ATS, you might just rename the C main() to c_main() or such and then call it from your ATS main()

extern fn c_main: (int, !argv) -> int = "ext#"

implement main
(argc, argv) = (
 
// all those dynload functions have already been called at this point
 
// now do your own stuff
 
// then call this until the Borg takes it as well:
  c_main
(argc, argv)
)

when C complains about type incompatibilities where there are none, you might just with "mac#" instead of "ext#"

your ATS types can of course be much more precise than expressed by your C prototypes. For example what_was() could return a linear string - ATS callers will care; C callers of course won't. Just note that ATS can't check your work to see that some_c_function_returning_a_pointer() really never returns NULL while that function is written in C. And, a reason to be more precise, is that if you lie to ATS, you can't blame it when you get a segfault :) A easy way to lie to ATS is to say that a C function returns a string when it actually returns NULL or else a string.

For working with C, I want to highlight a particular trick (which you can see In ATS's included PCRE bindings). As a complete example:

main.c:

#include <stdio.h>
#include <stdlib.h>

extern int think_deeply(void);

void setn (int *n) {
    *n = 21;
}

int main(void) {
    int ans = think_deeply();
    printf("the answer is: %d\n", ans);
    return 0;
}

deepthought.dats:

#include "share/atspre_staload.hats"

#define ATS_DYNLOADFLAG 0

extern fun think_deeply: () -> int = "ext#"
extern fun setn(&int? >> int): void = "ext#"

implement think_deeply() = n * 2 where {
        var n: int
        val () = setn(n)
}

usage:

$ ls
deepthought.dats  main.c
$ patscc -c main.c
$ patscc -c deepthought.dats
$ patscc main.o deepthought_dats.o -o think
$ ./think
the answer is: 42
$


which also exhibits a suggestion: use patscc to compile everything. The other way would be to use patscc just to generate the deepthought_dats.c file, after which you can be sure to use the same C compiler for everything.

cheers,

Brandon Barker

unread,
Jun 22, 2018, 2:39:46 PM6/22/18
to ats-lang-users
Thanks Julian,

This will be extremely helpful in getting me going and has already been great for jogging my memory.

Brandon Barker

unread,
Jul 1, 2018, 6:19:42 PM7/1/18
to ats-lang-users
I tried a few variants of the c_main example, but kept getting a similar error. For example:

extern fn c_main(argc: int, argv: !argv): int = "ext#"

Gives:

 75(line=4, offs=36) -- 79(line=4, offs=40): error(2): the static expression is of the sort [S2RTfun(S2RTbas(S2RTBASpre(int)); S2RTbas(S2RTBASimp(2; viewtype)))] but it is expected to be of the sort [S2RTbas(S2RTBASimp(7; view))]

Also, the error appears to be printed twice for some reason.

I'm curious where the expectation comes from since I'm just declaring the type/interface of the function.

Another issue I'm having in parallel - I'm liking the "compile everything with patscc" (only had to change one aspect of some C code in the project for it to work with C99 rules), but I'm still having some trouble getting the build to compile main.dats:

Makefile.in has

src     : 
        @echo ${OTHER} ${CFILES} ${HFILES} ${DATS_FILES} 

This is the only place CFILES is used, so DATS_FILES, would, I think be OK here. So I tried adding main.dats directly to CFILES, but I still get the same error:

gcc: error: main.o: No such file or directory

And indeed, I see no attempt to compile main.dats. I'll keep looking into this, but thought I'd post it in case someone familiar with autotools had any pointers.

Thanks,

gmhwxi

unread,
Jul 3, 2018, 3:09:32 PM7/3/18
to ats-lang-users

Note that 'argv' is a type constructor. What you need
is the following interface:

extern fn c_main{n:int}(argc: int(n), argv: !argv(n)): = "ext#"

Po-Yu Hsieh

unread,
Jul 5, 2018, 10:25:59 AM7/5/18
to ats-lang-users
I tried the deepthought example, (I use homebrew to install the latest version of ATS) but error occured when binding the two object files.

These are the warning messages showed when compiling both the C and ATS files:

clang: warning: argument unused during compilation: '-L/usr/local/Cellar/ats2-postiats/0.3.10/lib/ats2-postiats-0.3.9/ccomp/atslib/lib' [-Wunused-command-line-argument]
clang
: warning: argument unused during compilation: '-L/usr/local/Cellar/ats2-postiats/0.3.10/lib/ats2-postiats-0.3.9/ccomp/atslib/lib64' [-Wunused-command-line-argument]

And this is the error message (with verbose option):
Apple LLVM version 9.1.0 (clang-902.0.39.2)
Target: x86_64-apple-darwin17.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
 
"/Library/Developer/CommandLineTools/usr/bin/ld" -demangle -lto_library /Library/Developer/CommandLineTools/usr/lib/libLTO.dylib -dynamic -arch x86_64 -macosx_version_min 10.13.0 -o think -L/usr/local/Cellar/ats2-postiats/0.3.10/lib/ats2-postiats-0.3.9/ccomp/atslib/lib -L/usr/local/Cellar/ats2-postiats/0.3.10/lib/ats2-postiats-0.3.9/ccomp/atslib/lib64 main.o deepthought_dats.o -lSystem /Library/Developer/CommandLineTools/usr/lib/clang/9.1.0/lib/darwin/libclang_rt.osx.a
ld
: warning: directory not found for option '-L/usr/local/Cellar/ats2-postiats/0.3.10/lib/ats2-postiats-0.3.9/ccomp/atslib/lib64'
Undefined symbols for architecture x86_64:
 
"_setn", referenced from:
      _think_deeply
in deepthought_dats.o
ld
: symbol(s) not found for architecture x86_64
clang
: error: linker command failed with exit code 1 (use -v to see invocation)


Julian Fondren於 2018年6月22日星期五 UTC-4上午12時15分45秒寫道:

Hongwei Xi

unread,
Jul 5, 2018, 10:35:06 AM7/5/18
to ats-lan...@googlegroups.com
These are harmless warnings. Please ignore them.


--
You received this message because you are subscribed to the Google Groups "ats-lang-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ats-lang-users+unsubscribe@googlegroups.com.
To post to this group, send email to ats-lang-users@googlegroups.com.

Brandon Barker

unread,
Jul 5, 2018, 10:48:59 AM7/5/18
to ats-lang-users
For the error message bit: I saw it couldn't find a directory which might lead to the error. The directory in question was:

/usr/local/Cellar/ats2-postiats/0.3.10/lib/ats2-postiats-0.3.9/ccomp/atslib/lib64

I see there is a version mismatch - what is the closed to that you can find that does exist? Maybe 

/usr/local/Cellar/ats2-postiats/0.3.10/lib/ats2-postiats-0.3.10/ccomp/atslib/lib64

If that looks like it might be an issue, maybe upgrade to 0.3.11 (I seem to recall there was a versioning bug in 0.3.10, but not sure if this is related)

--
You received this message because you are subscribed to a topic in the Google Groups "ats-lang-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/ats-lang-users/DjbmPoC6mjM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.


--
Brandon Barker
brandon...@gmail.com
Message has been deleted

Po-Yu Hsieh

unread,
Jul 5, 2018, 11:06:18 AM7/5/18
to ats-lang-users
The latest version for ATS2 on homebrew is 0.3.10.

I checked the directory and found there's only one 'lib' directory under 'atslib'. And "ld: symbol(s) not found for architecture x86_64" error still occurs after removing 'lib64' path from command.

Brandon Barker於 2018年7月5日星期四 UTC-4上午10時48分59秒寫道:

Richard

unread,
Jul 5, 2018, 1:51:33 PM7/5/18
to ats-lang-users


On Thursday, July 5, 2018 at 10:25:59 AM UTC-4, Po-Yu Hsieh wrote:
I tried the deepthought example, (I use homebrew to install the latest version of ATS) but error occured when binding the two object files.

These are the warning messages showed when compiling both the C and ATS files:

clang: warning: argument unused during compilation: '-L/usr/local/Cellar/ats2-postiats/0.3.10/lib/ats2-postiats-0.3.9/ccomp/atslib/lib' [-Wunused-command-line-argument]
clang
: warning: argument unused during compilation: '-L/usr/local/Cellar/ats2-postiats/0.3.10/lib/ats2-postiats-0.3.9/ccomp/atslib/lib64' [-Wunused-command-line-argument]


When using patscc to compile c, patscc invokes gcc with the following by default:

gcc -std=c99 -D_XOPEN_SOURCE -I${PATSHOME} -I${PATSHOME}/ccomp/runtime -L${PATSHOME}/ccomp/atslib/lib

In this case, clang is saying that "-L${PATSHOME}/ccomp/atslib/lib" is unused.

Julian Fondren

unread,
Jul 5, 2018, 3:01:04 PM7/5/18
to ats-lang-users
Are you very sure that you accurately duplicated my code and my compilation steps? With Homebrew ATS2:

# brew link --overwrite ats2-postiats
Warning: Already linked: /usr/local/Cellar/ats2-postiats/0.3.10
To relink: brew unlink ats2-postiats && brew link ats2-postiats
# patscc -c main.c
clang: warning: argument unused during compilation: '-L/usr/local/Cellar/ats2-postiats/0.3.10/lib/ats2-postiats-0.3.9/ccomp/atslib/lib' [-Wunused-command-line-argument]
clang: warning: argument unused during compilation: '-L/usr/local/Cellar/ats2-postiats/0.3.10/lib/ats2-postiats-0.3.9/ccomp/atslib/lib64' [-Wunused-command-line-argument]
# patscc -c deepthought.dats
clang: warning: argument unused during compilation: '-L/usr/local/Cellar/ats2-postiats/0.3.10/lib/ats2-postiats-0.3.9/ccomp/atslib/lib' [-Wunused-command-line-argument]
clang: warning: argument unused during compilation: '-L/usr/local/Cellar/ats2-postiats/0.3.10/lib/ats2-postiats-0.3.9/ccomp/atslib/lib64' [-Wunused-command-line-argument]
# patscc main.o deepthought_dats.o -o think
ld: warning: directory not found for option '-L/usr/local/Cellar/ats2-postiats/0.3.10/lib/ats2-postiats-0.3.9/ccomp/atslib/lib64'
# ./think
the answer is: 42

Your error says that a 'setn' function is referenced but not supplied by any object file that you provide to the linker. With my code it should be supplied by main.o. If I edit my example to *only* change deepthought.dats to refer to setx instead of setn, I can get this very similar error, since main.o continues to provide setn but not setx:

# patscc deepthought_dats.o main.o -o think
ld: warning: directory not found for option '-L/usr/local/Cellar/ats2-postiats/0.3.10/lib/ats2-postiats-0.3.9/ccomp/atslib/lib64'
Undefined symbols for architecture x86_64:
  "_setx", referenced from:
      _think_deeply in deepthought_dats.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)



On Thursday, July 5, 2018 at 9:25:59 AM UTC-5, Po-Yu Hsieh wrote:
I tried the deepthought example, (I use homebrew to install the latest version of ATS) but error occured when binding the two object files.

Po-Yu Hsieh

unread,
Jul 5, 2018, 3:16:08 PM7/5/18
to ats-lang-users
You're right, I find that in my main.c, there's typo on the name setn, and that's where the error came from.
Now it works. Thanks!

Julian Fondren於 2018年7月5日星期四 UTC-4下午3時01分04秒寫道:

Brandon Barker

unread,
Jul 5, 2018, 8:10:48 PM7/5/18
to ats-lang-users
In the section http://ats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/HTML/x2080.html, I missed if it is also possible to define a value in ATS and then access it from C.  Is it possible?


On Friday, June 22, 2018 at 12:15:45 AM UTC-4, Julian Fondren wrote:

Julian Fondren

unread,
Jul 5, 2018, 9:00:30 PM7/5/18
to ats-lang-users
On Thursday, July 5, 2018 at 7:10:48 PM UTC-5, Brandon Barker wrote:
In the section http://ats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/HTML/x2080.html, I missed if it is also possible to define a value in ATS and then access it from C.  Is it possible?

C can work with datatypes as explained elsewhere in that chapter. Otherwise AFAIK your options are:
1. let C get the value by calling an ATS function
2. import a C pointer to ATS and let ATS set it

For #2, consider

#include "share/atspre_staload.hats"

extern fn putvars(): void = "ext#"
%{
int n[1];
int *m;
void putvars() { printf("n is: %d\nm is: %d\n", *n, *m); }
%}

val myval = 42
var myvar = myval
extvar "m" = addr@myvar
val () = myvar := myvar + 1

implement main0() = (
        $UNSAFE.ptr0_set<int>($extval(ptr, "n"), myval);
        putvars();
)

Hongwei Xi

unread,
Jul 6, 2018, 8:24:50 AM7/6/18
to ats-lan...@googlegroups.com

As long as you name the value:

#include
"share/atspre_staload.hats"

extern val fact10 : int = "ext#foo"

implement fact10 =
(fix f(x:int): int =>
 if x > 0 then x * f(x-1) else 1)(10)

implement
main0() =
println! ("fact10 = ", $extval(int, "foo"))


--
You received this message because you are subscribed to the Google Groups "ats-lang-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ats-lang-users+unsubscribe@googlegroups.com.
To post to this group, send email to ats-lang-users@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages