Getting Set Up as a CFA Developer ================================= Joining the Core Team --------------------- If you are a new student on the Cforall research team (or playing a similar "embedded" role), you need membership/access to: - ssh login on plg2.uwaterloo.ca => adding a plg2 account - push to the git repo cforall@plg.uwaterloo.ca:software/cfa/cfa-cc => adding plg2 ssh key into /u/cforall/.ssh/authorized_keys - log in to the bug tracker (to create/edit tickets that are publicly browsable): https://cforall.uwaterloo.ca/trac => add userid to /etc/apache2/conf.d/trac.conf - receive email notifications for git pushes, ticket edits, and build successes/failures => adding userid to Cforall mailing list - receive email broadcasts of the broader PLG: proglang-research@lists.uwaterloo.ca Note also the resources: - projet's public website: https://cforall.uwaterloo.ca/ - common build service, publicly browsable: https://cforall.uwaterloo.ca/jenkins/ - It orchestrates build+test on a dozen machines of varying architectures - It runs a ~10-min build+test after every push and emails the result - It runs a ~1-hour build+test nightly (plus, upon request to Peter) and emails the result - It's normal to push a change that was working locally, but have these more thorough tests tell you otherwise. No shame in "breaking the build," just get it fixed. (Usually, roll back your change if a fix will take more than a couple hours, but case-by-case discussion is common.) - When more info about a failure is needed than what's in the log attached to the email, it's often findable by browsing the Jenkins website - Direct email from you to all individuals in the core team is the best way to ask how something works, what an error message means, or so on. Kicking the tires ----------------- Read and do the instructions in cfa-cc/INSTALL, to get a working CFA compiler built from source. Many members of the core team do this (and much general work) on plg2. The program `cfa` is the driver, which acts like a command-line stand-in to the `gcc` command. Its source starts from cfa-cc/src/driver/cfa.cc. The driver runs `cfa-cpp`, which is the actual Cforall to C transpiler, while cfa is a wrapper command which runs the preprocessor, cfa-cc, and then the rest of the gcc compilation chain. The `cfa-cpp` source code starts from cfa-cc/src/main.cpp. Most CFA programs rely on `libcfa`, the CFA core runtime library. Its source is in `cfa-cc/libcfa/src`. It gets compiled while building CFA, into `(where-ran-configure)/libcfa/x64-debug/src/.libs/libcfa.so` and `libcfathread.so`. Your test programs link with it. Most CFA programs rely on "the prelude", which is a collection of headers that your test programs implicitly import. Its source is in cfa-cc/libcfa/prelude. It gets preprocessed while building CFA into `(where-ran-configure)/libcfa/x64-debug/prelude`, which is is compiled within your test programs. A variety of example CFA programs is available in cfa-cc/tests/**/*.cfa. They compile and run in a test-suite invocation as described in cfa-cc/INSTALL, as occurs under a Jenkins build, or as some prefer to run manually: pwd # assert in a build folder ./tests/test.py --all -j8 ./tests/test.py exceptions/hotpotato # just one test # see cfa-cc/tests/exceptions/hotpotato.cfa: source code # see cfa-cc/tests/exceptions/.expect/hotpotato.txt: running its ./a.out should print this Manual full test-program compilation, broken into stages: cfa test.cfa -CFA > test.lowered.c gcc -c test.lowered.c cfa test.lowered.o # link via our driver, to get libcfa ./a.out Lowering step, abbreviated to be more readable: cfa test.cfa -CFA -XCFA,-p Example of examining the CFA lowering at roughly its halfway point: cfa test.cfa -CFA -XCFA,-p,-Pascodegen,-Pexpranly -XCFA passes the argument/comma separated arguments to cfa-cpp. Get help on more -XCFA/cfa-cpp arguments: cfa test.cfa -CFA -XCFA,--help cfa-cpp --help Example of isolating a cfa-cpp invocation on your test program. Most useful for debugging the code under `cfa-cc/src`. The presentation assumes an install in the style that cfa-cc/INSTALL calls "side-by-side," though there are equivalents for all the styles. ./build/driver/cfa test.cfa -E > test.preprocessed.cfa ./build/driver/cfa-cpp test.preprocessed.cfa -p --prelude-dir ./build/libcfa/x64-debug/prelude gdb -args ./build/driver/cfa-cpp test.preprocessed.cfa -p --prelude-dir ./build/libcfa/x64-debug/prelude Debugging the cfa-cpp program is most productive in a "debug" configuration. (Whereas working on libcfa changes is more productive in a cfa-cc/INSTALL "vanilla" configuration.) An example of creating such a configuration, repeating the above gdb invocation within this configuration, and doing a basic tour of cfa-cpp data structures: mkdir build-gdb cd build-gdb ../cfa-cc/configure --with-target-hosts=host:debug CXXFLAGS='-O0 -g' make -j8 gdb -args ./driver/cfa-cpp ../test.preprocessed.cfa -p --prelude-dir ./libcfa/x64-debug/prelude b ResolvExpr::resolve run # stopped at breakpoint fini # in main, at the "rough halfway point" of -Pexpranly p transUnit.decls.size() # top-level: preulde+includes+yours set $lastDecl = transUnit.decls.back().get() # probably from your code: main? call CodeGen::generate( $lastDecl, std::cerr ) # like -XCFA,-Pexpranly,-Pascodegen call ast::print( std::cerr, $lastDecl, (Indenter){0,2} ) # like -XCFA,-Pexpranly # assuming $lastDecl is your program main, with argc/argv declared ... p *$lastDecl # assert an ast::FunctionDecl p ((ast::FunctionDecl*)$lastDecl)->params.size() # assert 2 set $argc_d = ((ast::FunctionDecl*)$lastDecl)->params[0].get() call CodeGen::generate( $argc_d, std::cerr ) call ast::print( std::cerr, $argc_d, (Indenter){0,2} ) # digging into argv gives sense of AST's granularity, utility of `call print` over dig-cast-`p` set $argv_d = ((ast::FunctionDecl*)$lastDecl)->params[1].get() call ast::print( std::cerr, $argv_d, (Indenter){0,2} ) p *$argv_d # assert an ast::ObjectDecl set $argv_t0 = ((ast::ObjectDecl*)$argv_d)->type.get() p *$argv_t0 # assert an ast::PointerType set $argv_t1 = ((ast::PointerType*)$argv_t0)->base.get() p *$argv_t1 # assert an ast::PointerType set $argv_t2 = ((ast::PointerType*)$argv_t1)->base.get() p *$argv_t2 # assert an ast::BasicType p ((ast::BasicType*)$argv_t2)->kind # assert ast::Char