Well here it is. The latest and greatest. Making its first appearance in POD, the "getting started" guide. There is a lot of work to do on it. There are sections that read like bad notes. But some might find this realease of use.
And in my tinkering around, I compile a lot. I have also added this handy little perl script that helps.
I only know that it works on win32 (XP). I could get it working on linux if anyone is interested.
Extensions are in win32 speak. But it uses Config.pm so it should be somewhat easy to make work for linux if it already does not. Here is a summary of what it does.
perl ecomp.pl -s dir
This builds a static libparrot.lib in the specified dir
perl ecomp.pl -d dir
This builds a dynamic libparrot.lib and libparrot.dll in the specified dir
perl ecomp.pl -o dir/test
this will compile dir/test.c into dir/test.obj (leave off all file extensions)
perl ecomp.pl -b dir/test
this will compile and link dir/test.c into dir/test.exe (leave off all file extensions). Handy when you just want to run something without the fuss.
perl ecomp.pl -link dir/test
this will link dir/test.obj with other parrot obj files to create dir/test.exe
perl ecomp.pl -liblink dir/test libdir/lib
this will link dir/test.obj with libdir/lib.lib (use libparrot for lib)
I think I know the answer, but is there a reason why in Config.pm 'so' maps to '.dll' and 'ar' only maps to 'lib' with no dot? Does it have to do with 'hello.lib' for windows and 'libhello.a' for linux?
Thanks,
Erik
=head1 TITLE Getting started with parrot
Version: 0.4 Status: POD DRAFT Last Revision: 19 October 2002 Maintained By: Erik Lechak <[EMAIL PROTECTED]> =head1 Introduction =head2 Overview This is the HOWTO for becoming a Parrot developer. It will outline the steps that will lead you to contributing to the Parrot community. I will start with the most basic material to ensure that anyone that would like to help can be brought up to speed. I am writing this as I learn the ropes as well. So hopefully I have some insight into the learning process. This document should also grow and become more useful as I grow more useful to the Parrot community. Although, writing a document about what you learn makes learning take a lot longer. =head2 Why would I want to help? There are a number of great reasons to help with Parrot. Several languages are slated to compile down to Parrot ByteCode (PBC). Perl, Python, and Java are just a few. I imagine that the list will continue to grow as Parrot does. The Parrot elevator (or cage) is close to the ground floor and it is waiting for developers to get on. This is a great chance to learn from some of the best programmers around. The chance to help merge the strengths and user bases of these languages is a great opportunity. Students looking for a great place to find a computer science project, should look no further than Parrot. There are many different areas in Parrot to choose from. From language development to garbage collection, Parrot provides a fertile ground for project ideas. If you have never worked on a open source project before, Parrot offers a great way to start. Working in some corporate environments can discourage creative thinking and novel approaches to software design and development. Working on an Open source project introduces you to an entirely different approach. There are millions of other reasons to help with Parrot, but I will just mention one more. Your ego. Just imagine when in a few years you go on an interview and they ask you if you know Perl or Python and you can say "Yep, I helped write the interpreter." How cool would that be? =head1 First Steps OK, let's start with some baby steps. You are sitting at work surfing the web or your a student trying to come up with an idea for a computer science project. You stumble across Parrot and want to learn more. Where do you go from here? Well Here are some of the first steps in gaining an understanding of what Parrot is, where it is heading, and how you can help. Browse through www.parrotcode.org (see 'http://www.parrotcode.org'). This is Parrot's home. You can find just about all the documentation for Parrot here. One of the best introductions to Parrot is the Parrot FAQ (see 'http://www.parrotcode.org/docs/faq.pod.html'). It is an easy to read and entertaining executive summary of Parrot. Most of the documentation is in the 'great reference material' category not the 'Parrot for dummies' category. Once you get better acquainted with Parrot, the documentation makes more sense. Remember that Parrot is a dynamic project, and that includes its documentation. Things are changing and being added all the time. Another great document to get you started with Parrot is the Parrot Primer (see 'http://www.parrotcode.org/docs/intro.pod.html'). Be aware that this document is a little dated (as of this release of this document). Read the Perl 6/Parrot Mailing List Summaries (see 'http://dev.perl.org/perl6/list-summaries/') (the newest ones can be found at perl.com (see 'http://www.perl.com')). Piers Cawley does a great job of summarizing the goings on in the group. He even suppresses some of the technobabble. Although he seems to portray me as being fixated on not liking pod. Or maybe its just me being fixated on not liking pod. The perl6-internals mailing list (see 'http://archive.develooper.com/perl6-internals@;perl.org/') is the group that will be most interesting to us (because we are talking about Parrot, not because Perl6 is not interesting). You can browse through the list just to get an idea of what Parrot development sound like. If you are new to Parrot don't spend too much time here trying to read and comprehend the mailing list. Most of the talk is about the internal components, and since you are new to Parrot, It will make very little sense. So now let's get your machine ready. So that you can download and start playing with Parrot. =head1 What Do I Need to Get Started =head2 Required Tools If you program in C and Perl, you already have the tools you need to build Parrot. This is the list of the tools that are required to do anything with parrot: =over 4 =item * An ANSI (??89 or 99??)I<C> compiler =item * a version of I<make> =item * I<Perl> 5.005_03 or up =back It goes without saying that since Parrot is being developed in C that you need a C compiler. If you have a C compiler and use it, chances are a version of make is also installed on your machine. There are several C compilers to choose from. Here are the listings of Parrot friendly C compilers for various operating systems: =over 4 =item * Linux =over 4 =item * gnu gcc =back =item * Windows =over 4 =item * Microsoft's Visual C++ =item * mingw =item * cygwin + gnu gcc =back =item * Macintosh =over 4 =item * ???? =back =back Make is a tool that directs the build of parrot. On windows machines using VC++, the utility is called 'nmake' and is installed with VC++. The manual for gnu make is here (see 'http://www.gnu.org/manual/make/html_node/make_toc.html'). Cygwin is a unix type environment that runs on Windows. It allows you to use many of the gnu unix tools and can support X. Perl is currently an integral part of the build process. There is some talk that it will be slowly be replace by Parrot bootstrapping itself into a full build. Perl is used up front in the configuration process. It is used to generate C code from ops and pmc files. Most if not all of the Parrot utility programs are written in Perl. And the list goes on. You can get the latest and greatest Perl and a ton of neat modules at CPAN (see 'http://www.cpan.org'). If you want a pre built binary version of Perl for Win32 go to ActiveState (see 'http://www.activestate.com'). Perl is also required for some of the languages that come with the parrot distribution. See the L<included languages|"Included Languages"> section below. =head2 Important Tools These are some tools that are not required to build or run Parrot, but if you plan on doing any development work, they are necessary: =over 4 =item * cvs =item * diff =item * your favorite text editor =back CVS is the 'Concurrent Versions System'. It is the source code control system that this project and the majority of other open source projects employ. CVS information and applications can be found at www.cvshome.org (see 'http://www.cvshome.org'). If you are using windows go to www.wincvs.org (see 'http://www.wincvs.org') for a client that will work on your machine. There is a source code repository on cvs.perl.org. This is where the developers check the source code out of, and after modifying it, check it back into. Look L<here|"Getting the Parrot Source Code"> for a quick intro to cvs. You can get the cvs manual here (see 'http://www.cvshome.org/docs/manual'). Diff is a utility useful in determining the differences between two files. It is also used to generate patches that can be applied to the Parrot repository. =head2 Useful Tools Here are some other utilities that may come in handy. They are not mandatory for building Parrot, but they are handy to have around: =over 4 =item * pod2text =item * pod2html =item * perldoc =item * grep =item * patch =back The utilities I<pod2text> and I<pod2html> transform the documentation provided with parrot into easier to read formats. They are provided with your Perl distribution. The parrot documentation comes in a format developed by the perl community called POD (Plain Old Documentation). Running these scripts on the POD file (or Perl script) of you choice will transform it into either text or html (respectively). See below for the calling syntax. Grep is a tool that the unix community is familiar with, but windows users may not recognize it. Grep locates occurrences of patterns in a file, or set of files. It comes in handy when you just can't find where that structure is defined or the place where that function is used. =head2 Language Development Tools If you plan on working on or building your own language for Parrot, these tools may come in handy. IMCC development (see ??????) requires lex and yacc. =over 4 =item * Parse::RecDescent =item * lex/flex =item * yacc/bison =back Lex is a tokenizer. A tokenizer takes a stream of characters and cuts them up into recognizable chunks called tokens. For example the string of characters you are currently reading can be broken into meaningful chunks called words. Yacc takes the tokens supplied by lex and looks for recognizable patterns in the tokens. When it recognizes a pattern, it performs a specified function. To continue the analogy started above, the words are linked together to form a sentence which is (I hope) a coherent thought. Parse::RecDescent is a module for Perl. It is like lex and yacc mixed into one creature. You could use this module to create a language for Parrot or use it to learn the basics of what lex and yacc provide. This was just a brief description of lex, yacc and recursive descent parsing. For a more detailed description of these programs and concepts see ????? Now your machine is ready for Parrot. So we need to get the code. =head1 Getting the Parrot Source Code You can get instructions that might be more up to date for downloading the Parrot source code from www.parrotcode.org (see 'http://www.parrotcode.org') in the 'How to get the code' section. =over 4 =item * B<Browse the CVS Repository:> If you're just interested in browsing the CVS repository without downloading anything, a few interfaces exist. =over 4 =item * cvs.perl.org/cvsweb/parrot/ (see 'http://cvs.perl.org/cvsweb/parrot/') =item * cvs.perl.org/viewcvs/parrot/ (see 'http://cvs.perl.org/viewcvs/parrot/') =back =item * B<Download Snapshot of the CVS Repository:> The easiest solution is to grab the most recent snapshot of the Parrot CVS repository. It's a tar-gzipped download of a recent checkout of Parrot, updated every six hours. You can find it here: =over 4 =item * cvs.perl.org/snapshots/parrot/parrot-latest.tar.gz (see 'http://cvs.perl.org/snapshots/parrot/parrot-latest.tar.gz') =back =item * B<Use CVS to get the code> Even better is the option to use CVS, which gets you the very latest copy of the Parrot distribution. The procedure for this is: =over 4 =item * Install cvs on your machine (make sure the cvs executable is in your path). =item * Tell cvs where to find the Parrot repository and log in to it. The environment variable CVSROOT holds the location of the repository. Here are a few shell scripts to use so you don't have to retype this all the time: =over 4 =item * Batch script for Windows =over 4 set HOME=C: set USERPROFILE=C: set CVSROOT=:pserver:[EMAIL PROTECTED]:/cvs/public cvs login =back =item * Bash script file for Linux: *untested* export CVSROOT=:pserver:[EMAIL PROTECTED]:/cvs/public cvs login =back =item * Run the appropriate script above for your system. Hit the enter key when is asks you for you password. =item * If you want to create a new instance of the source code on your machine, you need to check the source code out of the Parrot repository. If you have already checked out the copy you only need to update it, so skip to the next item. To check out the parrot source code go to the directory where you want the parrot root directory to be created, then type: cvs co =item * You only have to check out the source code once. From now on you can just sync the version on your machine with the repository. The following command is recursive so it will update the current directory and all the lower directories. To update your version, I<cd> into the Parrot root directory and type: cvs update -dP =back =back CVS has a ton of commands. Checkout and update have many flags. Please read the cvs manual (see 'http://www.cvshome.org/docs/manual') for more details and capabilities. =back You are now the proud owner of copy of Parrot. Let's take a look at what you have. =head1 Contents of the Distribution =over 4 =item * chartypes =item * L<classes|"PMCs"> - pmc directory =item * L<config|"Configuring Parrot"> - data for Configure.pl =item * L<docs|"Documentation"> - POD documentation for Parrot =item * editor - Nice plugins for emacs and vi =item * encodings =item * examples =item * icu =item * include - Parrot C header files =item * io =item * jit - Just In Time "compiler" =item * L<languages|"Included Languages"> - Current set of languages that support Parrot =item * lib - Perl module library =item * LICENSES - Parrot's license files =item * L<t|"Testing"> - All of the code test for I<make test> =item * tools =item * types =item * MANIFEST - list of files in the parrot distribution =item * README - first thing you should read after downloading Parrot =item * vtable.tbl - virtual functions supported by PMCs =item * *.pl - executable perl scripts =item * *.ops - opcode functions =back =head2 Executable Scripts =item parrot assemble.pl - compiles parrot assembly code (.pasm) into parrot bytecode (packfiles) Configure.pl - first step in the Parrot build process disassemble.pl - transforms packfiles into assembly code (.pasm) jit2h.pl make.pl - perl "make" program that will build Parrot ops2c.pl - translates opcode files (.ops) into C code ops2cgc.pl ops2pm.pl optimizer.pl - performs optimization techniques on parrot assembly code file (.pasm) pbc2c.pl - generates the equivalent C code of parrot byte code (packfile) vtable_h.pl - generates parrot/include/vtable.h C header file =item parrot/t harness - runs the parrot tests (i.e. 'perl t/harness t/src/basic.t') =item parrot/classes genclass.pl - generates a blank PMC template pmc2c.pl - creates a C file based on the .pmc file =item parrot/tools/dev check_source_standards.pl - looks for violations of coding standards genrpt.pl lib_deps.pl maincheck.pl - verifies the contents of the distribution with the MANIFEST file parrot_coverage.pl run_indent.pl =item parrot/types bignum_atest.pl bignum_test.pl =head1 Connecting with the Parrot community I couldn't decide whether to put this section before or after I show you how to compile Parrot. It probably should go after, but for now it is here. Just in case Parrot will not compile on your machine, I want you to be able to contact the Parrot community to get some help. Now might be a good time to think about how you can help with Parrot. Where do you skills lie? How much time can you devote to the project? This document will try to touch on several different ways to help with Parrot. Here are some of them: =over 4 =item * Help with the documentation =item * Code development =item * Write a Language that compiles to PBC =item * Testing =item * Others??? (raise funds, buy a developer a pizza, ...) =back =head2 perl6-internals mailing list The first step is looking at the mailing list. The web interface to the mailing list archive is at perl6-internals mailing list archive (see 'http://archive.develooper.com/perl6-internals@;perl.org/'). You can subscribe to the mailing list by sending a blank email to [EMAIL PROTECTED] (see 'mailto:perl6-internals-subscribe@;perl.org'). After you mail in the subscription request, an email with a set of instructions will be sent to you automatically. When you receive that email, It will ask you to reply to it to ensure that you want to subscribe to the mailing list. This protects you from nefarious netizens that want to get you involved in Parrot without your consent. If you want to ask a question or post something to the mailing list send an email containing your message to [EMAIL PROTECTED] (see 'mailto:perl6-internals@;perl.org'). This will put your message in the root of the mailing list archive. If you want your message to be a reply to a previous message, go to the message you want to reply to and hit the 'reply' button. Then type your reply in. And that's all there is to it. Before we get to Compiling and trying out Parrot, let just go over some of the documentation. =head1 Documentation As with most programs the best place to start when you download anything is with the README file (in the parrot root directory). It cuts right through the small talk and quickly gets you up and running. The Parrot documentation is in the parrot/docs directory. This is the current makeup of the parrot documentation directories: =over 4 =item parrot/docs =over 4 This is where parrot concepts are explained, or miscellaneous topics are documented. =back =item parrot/docs/dev =over 4 This directory contains documents that describes the content and the functionality of individual source files. These files describe the implementation. The name of the document should match the name of the source code file that it describes. =back =item parrot/docs/pdds =over 4 This directory contains the parrot design documents. The design documents are a great place to get an overview of the direction parrot is heading. =back =back The documentation provided with parrot is written in pod. Pod is an embeddable documentation syntax for perl. See L<A brief introduction to pod> for more details. =head2 Translating Pod If you are having difficulty reading the documentation in pod and you have perl, you already have the tools to format pod into simple text or HTML: =over 4 =item * Transform pod into a text file pod2text file.pod > file.txt =item * Transform pod into an html file pod2html file.pod > file.html =back Some of the documentation for Parrot is embedded in the source code. During a build, this information is extracted and placed in the documentation directories. This keeps the documentation and the source code in sync (or it makes it simpler to keep things in sync). The code that extracts the pod from the source is in parrot/docs/Makefile (this Makefile does not exist before you build parrot). The following is one of the rules in parrot/docs/Makefile that creates a document from source (see ???? for a description of I<make rules>): core_ops.pod: ../core.ops perldoc -u ../core.ops > core_ops.pod =head2 A brief introduction to pod A more complete document about pod can be viewed by typing this at the command prompt (if you have perl installed): perldoc perlpod Pod is a commenting style/language for Perl. Its purpose is similar to that of javadoc. Pod comments can be embedded into Perl code or stand on their own in a separate file. If a file contains just pod, the standard file extension is .pod (as in 'document.pod'). To start a pod comment an equal sign (=) must be the first character of a line followed directly by a pod command. After the command is the content. The content varies based on the command. The pod '=cut' will end a pod section. For example: =head1 NAME This is what pod looks like =cut The blank lines are mandatory. In pod 'head1' declares a major heading. If you ran this pod through I<pod2text>, you would get something like: NAME This is what pod looks like The following list shows the pod commands and gives a brief description of them: head1 [heading name] - Major heading head2 [heading name] - Less Major heading head3 [heading name] - Even less Major heading over [number of spaces to indent] - Indented section( starts items). item [*,number,name] - This is a list item. for [format] - Formatter specific line begin [format] - Formatter specific section end - Ends a formatter specific section back - This ends an over section of pod. cut - Terminates the current section of pod. You may have as many pod sections that you want in a single file. Pod section do not nest ('over' section can nest). Once a '=cut' is reached all pod is turned off until another section is started. Pod also allows you to emphasize or give special treatment to text. Pod sequences are used for this purpose. When the pod is translated into another format, the sequence information might not look the same. The way that the translated text appears is the job of the pod formatter. For example if in pod you specify that hello be bold, and you translate the pod via pod2text, the result will be *hello*. However, translating the same pod into html will result in <B>hello</B> The following list describes the sequences and their functions: B - Bold I - Italics C - Code, put this around a block of code. S - ??? L - Make a link Z - Nothing E - Escape the character OK. Enough about POD and documentation let get the show on the road. =head1 Compiling =head2 The very basics =over 4 =item * I<cd> to your parrot directory and run I<Configure.pl> (or perl Configure.pl on a Windows machine). This script performs a number of tests and configures parrot for a build on your machine (see Configuring Parrot below). The main result from running I<Configure.pl> is the generation of Makefiles. cd parrot perl Configure.pl =item * Run I<make> to compile everything and build parrot (I<nmake> with VC++). make =item * Run I<make test> to run the test suite and verify that everything works on your system. (Note: I found that if I ran the tests in a path where there were spaces, some of the tests failed. This may have been fixed) make test =back =head2 Configuring Parrot The main task of Configure.pl is to run a series of small perl scripts that perform the individual steps of prepping Parrot for a build. Here are some of the functions of Configure.pl: =over 4 =item * Determine information about your compiler and linker =item * Gather information about your OS =item * Run several test to determine ???? a bunch of stuff =item * Build Makefiles =item * Build documentation from source code (actually pod) =item * Translate pmc files into c files. =item * Translate ops files into c files. =back The scripts are in the parrot/config directory. This is a brief description of the directories: =over 4 =item config/ Root directory for configuration data used by Configure.pl =item config/init Scripts that set compiler and linker options =item config/init/hints OS dependant variables stored here =item config/inter =item config/auto Scripts that automatically detect correct settings =item config/auto/* Auxiliary files needed by auto scripts =item config/gen These scripts generate other files (like Makefiles and some =item config/gen/* Auxiliary files needed by gen scripts =back Just because a file appears in the config directory does not mean that it will be used. The perl module parrot/lib/Parrot/Configure/RunStepsHere.pm contains a list of the scripts to run. To run an additional script during configuration just add the scripts to the list. The scripts run in the order that they are listed. Here is an abbreviated list from RunStepsHere.pm just so you will know where to look (the ... means that I removed some scripts to save space. Don't put ... in the list): =over 4 # EDIT HERE TO ADD NEW TESTS @steps=qw( init/manifest.pl init/data.pl init/miniparrot.pl init/hints.pl ... ); =back As of the last version of this document, these are the scripts that Configure.pl runs: * init/manifest.pl ensures all files listed in manifest are present includes: ExtUtils/Manifest(perl standard lib) * init/data.pl gets data about compiler, linker, make util includes: parrot/lib/Parrot/Configure/Step; * init/miniparrot.pl Should we build miniparrot???? * init/hints.pl customizes some configuration data based on the platform. An addendum to init/data.pl??? * init/debug.pl enables debugging * inter/progs.pl another step that deals with getting compiler and linker options * inter/types.pl customizes the size of the different parrot types (intval floatval and pcode) * inter/ops.pl determine the ops files that should be compiled into parrot. Looks like all ops files but one named vtable.ops (that I don't have in my distribution) are used. * inter/exp.pl experimental networking ?????? * inter/pmc.pl What pmc files should be included in the build. All of the pmcs in the parrot/classes directory * auto/alignptrs.pl * auto/headers.pl * auto/sizes.pl * auto/stackdir.pl * auto/byteorder.pl * auto/pack.pl * auto/format.pl * auto/gcc.pl * auto/jit.pl * auto/funcptr.pl * auto/cgoto.pl * gen/config_h.pl * gen/config_pm.pl generates the super helpful lib/Parrot/Config.pm. This module lists all of the machine dependent variables and gives them a non-system dependent hash entry. * gen/makefiles.pl generates the main Makefile, the documentation Makefile, the pmc makefile (in the classes directory), and the Makefiles for the various languages included with Parrot. * gen/myconfig.pl * gen/platform.pl * gen/libparrot_def.pl Takes the data from libparrot_def/libparrot_def.in and creates the libparrot.def file. This file is used in Win32 to create the libparrot dll. * gen/core_pmcs.pl =head2 Making Parrot After configuring Parrot you are ready to take the largest step so far. You are going to build Parrot. For such a daunting and important step, It is kind of anticlimactic that all it takes is: make Or for Windows with VC++: nmake That's it. Just type I<make> at the command prompt and you can sit back and watch in amazement as Parrot is built.(Or you can go to the fridge.) =head2 Other Make targets This is a brief description of some of the other targets in the Makefile. A target in a makefile is something that you can run by typing: make target The following is a list of targets provided by the generated file Makefile: =over 4 =item * shared - creates the parrot shared library (.so or .dll) =item * test - runs the parrot tests =item * quicktest - runs the parrot tests (only if test has already been run) =item * clean - removes files built during the make process =item * realclean - removes files built during make and Configure.pl process =back =head2 Compliling Notes In a utopian world I<make> would build everything. And everything would work. However, it is often necessary to build the libraries, objects, and executables yourself. If for no other reason than to satisfy your own curiosity about how the process works. The first step in figuring out how the build process works is to look at the Makefile. If you are familiar with Makefiles, it is all you need to know to piece together a command line that will build whatever you want. Different platforms (Linux, Win32, ...) support different tools and the same tools on different machines can have different names. For example, a C compiler can be I<gcc>, I<cc>, or I<cl> and building a library could require something called I<ar> or I<link>. The configureation process builds a Makefile that decouples the build syntax from the machine type and the software installed. It does this by creating variables that remove the machine and software dependence. Then throughout the remainder of the Makefile only the variables are used. Another file is built with these variables. It is lib/Parrot/Config.pm. The majority of variables found in the Makefile have the same name in the Config.pm file, but they are in lower case (a few variables do differ). Instead of going through the process of trying to figure out what the command line should be to build Parrot's pieces, you can use the Config.pm file to help you accomplish this. An example of the use of the Config.pm module is in the parrot/lib/Parrot/Test.pm module. Here is an excerpt (Note that the code may change so the examples may not match the code exactly): _run_command("$PConfig{cc} $PConfig{ccflags} -I./include -c $PConfig{cc_o_out}$obj_f $source_f", 'STDOUT' => $build_f, 'STDERR' => $build_f); _run_command("$PConfig{link} $PConfig{linkflags} $obj_f $PConfig{ld_out}$exe_f blib/lib/libparrot$PConfig{a} $PConfig{libs}", 'STDOUT' => $build_f, 'STDERR' => $build_f); The following is a pseudo-perlscript that demonstrates how lib/Parrot/Config.pm can be used to remove the OS specific nature of building: use lib "c:/parrot/lib"; use Parrot::Config; ##Find the object files my $o_ext = $PConfig{'o'}; my @o_files=(); push(@o_files, glob( "*$o_ext" ) ); #root objects push(@o_files, glob( "classes/*$o_ext" ) ); #pmc objects push(@o_files, glob( "encodings/*$o_ext" ) ); #encoding objects push(@o_files, glob( "chartypes/*$o_ext" ) ); #chartype objects push(@o_files, glob( "io/*$o_ext" ) ); #io objects @o_files = grep (!/test_main/ , @o_files); #remove the obj with function main my $o_files = join (" " , @o_files); #join into a string ##Builds a static library (tested on Win32 system) `$PConfig{ld} -lib $PConfig{ld_out}libparrot$PConfig{ar} $o_files`; ##Builds a dynamic library `$PConfig{ld} $PConfig{ld_shared} $PConfig{ld_shared_flags} $PConfig{ldflags} $PConfig{ld_out}libparrot$PConfig{so} $o_files $PConfig{libs}`; ##Compile Parrot `$PConfig{cc} $PConfig{ccflags} -I./include -c $PConfig{cc_o_out}OUTNAME SOURCE`; ##Link with dynamic library (note: in win32 libparrot.dll need to be in path) `$PConfig{link} $PConfig{linkflags} $o_files $PConfig{ld_out}$exe_f blib/lib/libparrot$PConfig{a} $PConfig{libs}`; ##Link with object files `$PConfig{link} $PConfig{ld_out}OUTPUT.exe $PConfig{linkflags} OBJECTFILES OUTPUT.obj $PConfig{libs}`; =head1 Testing =over 4 =item t/ the test directory =item t/src tests for embedding and building parrot (C code tests) =item t/op tests for all of the opcodes =item t/pmc pmc specific tests =back Testing sounds like it may be a boring subject. But this is actually a great place to take a look at the current functionality of Parrot. Whenever someone adds some sort of capability to Parrot, a test is also installed that will test that funtionality. For those people that learn faster from code examples, the test (t) directory is your encyclopedia. Automated testing is conducted by the perl script t/harness. You can run individual test using harness like this (do this from the parrot root directory): perl t/harness t/src/basic.t This will run all of the tests in the t/src/basic.t file. A file with a ".t" extention is a test file. You can replace basic.t with any other test file or write your own tests and run them. This is a great way to try out the capabilities of Parrot and have the compilation and execution of your test automated. There are a number of "testing functions" that can be employed by t/harness. These functions are located inside of the test files (.t) and provide information to harness about how to run the tests. output_is - code is Parrot opcode, output must match expected output output_isnt output_like c_output_is - code is in C, output must match expected output c_output_isnt c_output_like If you are unfamiliar with Perl, the test files' syntax might look a little awkward (especially the '<<' in some subroutines arguments). So I will walk through an example. 1 use Parrot::Test tests => 2; 2 3 output_is(<<'CODE', '1', "print 1"); 4 print 1 5 end 6 CODE 7 8 output_is(<<'CODE', <<OUTPUT, "print string with embedded newline");| 9 print "Parrot flies\n" 10 end 11 CODE 12 Parrot flies 13 OUTPUT The line numbers up front are there so I can refer to the lines. They are not actually in the files. Line 1 shows how many tests this file contains. In this example there are two tests (I<tests => 2>). The tests follow the following syntax: output_is(test_source_code , expected_output , test_name); The first argument to the subroutine I<output_is> is a string that contains the source code that makes up the test. The second argument is the result that constitutes a passed test. The third argument is the name of the test. The first test in the example starts on line 3. Let me translate line 3 into english and it might clear up some things. Run a test called 'print 1'. The test consists of the code from the following lines up to but not including the word 'CODE'. The output of the test should be '1' to pass. Any other value is a failure. The << (for here) operator is a handy Perl operator that provides a way of specifying a string that can contain several lines and a lot of text in a pleasent syntax. The <<'CODE' will be replace with the text following the current line up to but not including the word CODE. The text that replaces that statement will be single quoted as specified by the single quotes around the word CODE. Lines 8-13 show a slightly more complicated use of the 'for here' operator. Both the source code and the expected value are specified by the 'for here' operator. The test code goes up to the word CODE. The expected output of the test starts the line after CODE and up to but not including the word OUTPUT. Which is a long way of saying "Parrot files". If you are interested in more feature and the internals of the testing environment see parrot/lib/Parrot/Test.pm and parrot/lib/Test/Builder.pm. =head2 TODOs Every once in a while you will see an area of a test blocked off so that a particular operating system will skip the test. In this example Win32 is excluded from this test: TODO: { local $TODO="t/src doesn't work on Windows" if $^O =~ /Win32/; $TODO=$TODO; #warnings ... ... ... } =head1 Developing =head2 Common CVS Just some notes!! cvs co cvs ci cvs update -dP cvs diff =head2 Patches =head3 I've developed a patch. What should I do with it? There's a lot of traffic that goes through the mailing list, and it's quite possible that if you send patches directly to the mailing list, they will get lost in the mailboxes of those with commit access. As such, a better solution would be to submit your patch to RT, the request tracker system that maintains bugs and patches for the Parrot project. To visit RT, go here: http://bugs6.perl.org/ Or if you want to submit a patch, send an email to [EMAIL PROTECTED] with the moniker [PATCH] (including the brackets) at the start of the subject so that it can be appropriately tagged in the RT system. Please note that you do I<not> have to CC [EMAIL PROTECTED] when reporting a bug. The RT system will correctly handle that on its own. A listing of the pending patches can be found here: http://www.parrotcode.org/openpatches =head3 I've found a bug, what now? Well, if you know enough about the bug that you can fix the problem, please do so. Then you can create a patch and submit it to the list, with a better chance of your bug getting attention. If you're not able to solve it on your own, we're still interested in seeing what the problem is, and hopefully helping to resolve it. To report a bug, email [EMAIL PROTECTED] with a brief description of your bug in the subject. For more information about the bug management system, see the previous question. =head3 How to submit a patch These are the steps to submit a patch: =over 4 =item 1 do a I<cvs update -dP> =item 2 do a I<cvs diff -u> of the file(s) you want to patch (note: Win32 users will probably need -ub) =item 3 redirect the output to a file (any name will do, .patch extension is conventional) =item 4 create a new email message =item 5 set the recipient to: [EMAIL PROTECTED] (note there's no need to CC the mailing list, it will find its way to it) =item 6 pre pend [PATCH] to the subject =item 7 be very, very informative about what you're doing, both in the subject line and the message body =item 8 attach the patch file you generated in step 2 (DON'T paste the content in the body, attach the file!) =item 9 send and wait patiently. =back =head1 Parrot Internals It's time to look at some of the types you will encounter in the Parrot code. One of the first places you should look when you start working on the internals of Parrot is F<'include/parrot/config.h'>. This file is generated when you run Configure.pl. This header file defines all of the main types and a lot of other bits and pieces that are used throghout Parrot. =head2 Common types =over 4 =item * INTVAL An integer value. See include/parrot/config.h for typedef. =item * FLOATVAL A float value. See include/parrot/config.h for typedef. =item * L<PMC|"PMCs"> A low level Parrot object. See pmc.h and the PMC section below. =item * L<STRING|"STRINGs"> Parrots String object. See string.h and string_funcs.h for details. =item * DPOINTER A pointer (of type void *) =item * L<VTABLE|"VTABLE"> A pointer to a table of functions. See vtable.h. =back =head2 Lingo for this section This section is huge and can be confusing. In order to keep things clear I will refer to things in a shortened version than what you might find in the code. This will make things clearer as you read this section. If you see slashes surrounding a word that means see this file for the code. For example, /interpreter.c/ means look in the file interpreter.c for the definition of the function or variable I am speaking about. I am not going to give paths for the files I refer you to in this section. I would be typing all night and all of the extra characters will just confuse the issue. So if I refer you to a '.c' file it is either in the parrot root directory or in the classes/ directory. If I refer you to a '.h' file it is in the include/parrot/ directory or in the classes/ directory. Any other extension is usualy in the parrot root directory. If it is not, I will give the directory it is in. This is where grep comes in handy. If you do not have grep get a copy and learn to use it. grep Parrot_new *.c - this will look through all of the .c files for Parrot_new There are many different types of PMCs. And the number is ever increasing as Parrot is developed. Each PMC types have two different names. The first is the easy name that people refer to them as (i.e. PerlInt). The second name is actualy an enumeration that C understands. C does not have the nice object oriented symantics that Object oriented languages do. In Parrot the PMC objects' types are defined by an enumeration (see core_pmcs.h for the enumeration definition). Or at least to create the PMC object you need to specify what PMC type by its enumeration. The enumerations look like I<enum_class_PMCTYPE>. For example, in the classes/ directory there is a PerlHash.pmc file. This means that there is a PerlHash pmc type. Inside of the C code that type would be refered to as enum_class_PerlHash. Here is a line of C code that creates a new PerlInt pmc. Note the enum_class_PerlInt as the final argument: pmc=pmc_new(interpreter, enum_class_PerlInt); I will abbreviate some of the funtion definitions into a pseudo c-like syntax. This is to save on wrist wear and tear. But I will also try to point you to the file that the function is defined or used in with the slash syntax described earlier. =head2 The Interpreter The struct Parrot_Interp is an interpreter object. Here is the code to create an interpreter: 1 #include "parrot/parrot.h" 2 #include "parrot/embed.h" 3 int main(int argc, char* argv[]) { 4 struct Parrot_Interp * interpreter; 5 interpreter = Parrot_new(); 6 } Line 2 includes embed.h. This file contains the declaration for Parrot_new(). Line 4 declares the variable I<interpreter> as a Parrot interpreter. Line 5 creates the interpreter. That's it. Kind of a boring program, but it's good to start small. Let's take a more detailed look at what Parrot_new does: Parrot_new /embed.c/ init_world /global_setup.c/ string_init parrot_initialize_core_pmcs Parrot_base_classname_hash = pmc_new(NULL,PerlHash) Parrot_register_coer_pmcs(Parrot_base_classname_hash) make_interpreter creates interpreter initializes variables in interpreter mem_setup_allocator(interpreter) Perl_stash = mem_sys_allocate Perl_stash->stash_hash = pmc_new(PerlHash) initialize register chunks initialize registers =head2 Memory management types Sorry, Just some notes for now. Parrot_Interp /interpreter.h/ Stash /resources.h/ Arena /resources.h/ Memory_Pool /resources.h/ Memory_Block /resources.h/ Small_Object_Pool /smallobjects.h/ Small_Object_Arena /smallobjects.h/ Parrot_Context /interpreter.h/ SYNC VTABLE Buffer /resources.h/ =head2 PMCs Parrot Magic Cookies (PMC). This is the meat and potatoes of Parrot (or beans and rice if you are a vegetarian). PMCs are the low level objects in Parrot. Every PMC in Parrot has a set of functions that must be defined for it. This set of mandatory funtions can be seen in the F<vtable.tbl> file. See the L<VTABLE> section below for more detail. See F<docs/vtables.pod> for a more detailed description on how to create a PMC. The following list details the contents of the PMC struct: VTABLE *vtable INTVAL flags DPOINTER *data UnionVal cache SYNC *synchronize PMC *next_for_GC =head3 creating a pmc Now we know what is in a PMC. So lets find out how to instanciate one. The first thing you need to know is what kind of PMC do you want to create. A quick glance and the F<classes/> directory will tell you what you have to choose from. You can also look in the file F<inclue/parrot/core_pmcs.h> and that will list the complete enumeration name of the PMC type. Once you know what type you want to create the name of the type is in the following form enum_class_PMCNAME The following functions allow you to create the new PMC objects: =over 4 =item * pmc_new(interpreter, type) =item * pmc_new_noinit( interpreter, type , size) =item * pmc_new_sized(interpreter, type, size) =item * pmc_new_sized_pmc(interpreter, type, pmc) =back Allright enough talk, let's write some code that does something. Well it doesn't do much but at least it's code. The following C code creates a Parrot interpreter and creates a PerlInt PMC: 1 #include "parrot/parrot.h" 2 #include "parrot/embed.h" 3 4 int main(int argc, char* argv[]) { 5 int dummy_var; 6 PMC *pmc; 7 8 struct Parrot_Interp * interpreter; 9 interpreter = Parrot_new(); 10 11 pmc=pmc_new(interpreter, enum_class_PerlInt); 12 pmc->vtable->set_integer_native(interpreter, pmc, 1); 13 } A closer look at what pmc_new does: pmc_new new_pmc_header pmc->vtable=Parrot_base_vtables[type] pmc->vtable->init(interpreter,pmc) =head3 pmc flags 0 - for use by pmc author 1 - for use by pmc author 2 - for use by pmc author 3 - for use by pmc author 4 - for use by pmc author 5 - for use by pmc author 6 - for use by pmc author 7 - for use by pmc author 8 - Set if the PMC has a destroy method that must be called 9 - ?????? 10 - Set to true if the PMC data pointer points to something that looks like a string or buffer pointer 11 - Set to true if the data pointer points to a PMC 12 - Set to true if the PMC has a private GC function. For PMCs the GC system can't snoop into 13 - Set to true if the PMC has a custom mark routine 14 - Are we live 15 - Are we on the free list 16 - Our refcount 17 - Our refcount 18 - Constant flag =head3 data =head2 VTABLE Every PMC type has its own vtable. A vtable defines the functional capabilities of a PMC. After building Parrot (or running pmc2c.pl), you can view all of the functions available to a PMC type by looking at the I<pmctype>.c file (like PerlInt.c). For example if you are interested in the PerlHash PMC type, look in the PerlHash.c file. At the end of the file you will see a function called I<Parrot_PerlHash_class_init>. If you were interested in PerlArray look int the PerlArray.c file for a function called I<Parrot_PerlArray_class_init>. I think you get the point. In this funciton a _vtable struct named temp_base_vtable defines the vtable. 1void Parrot_DemoPMC_class_init (int entry) { 2 3 struct _vtable temp_base_vtable = { 4 NULL, 5 enum_class_DemoPMC, 6 ... 7 ... 8 ... 9 Parrot_DemoPMC_substr_str_keyed, 10 Parrot_ParentPMC_substr_str_keyed_int, 11 Parrot_default_invoke 12 }; 13 14 Parrot_base_vtables[entry] = temp_base_vtable; 15 } The vtable or VTABLE type is a struct that contains pointers to all of the functions in F<vtable.tbl>. The VTABLE type is defined in F<include/parrot/vtable.h>. Actually struct _vtable is defined there. It is typedef'd into VTABLE in F<config.h>. Need to talk about inheritence and the syntax used in a .pmc file. =head2 STRINGs Just some notes for now!! #define STRING struct parrot_string_t typedef struct parrot_string_t String; =head3 String internals struct parrot_string_t { void *bufstart; UINTVAL buflen; UINTVAL flags; UINTVAL version; UINTVAL bufused; void *strstart; UINTVAL strlen; const ENCODING *encoding; const CHARTYPE *type; INTVAL language; }; typedef struct { void *bufstart; UINTVAL buflen; UINTVAL flags; UINTVAL version; } Buffer; =head3 String flags 0 can be used by programmer 1 can be used by programmer 2 can be used by programmer 3 can be used by programmer 4 can be used by programmer 5 can be used by programmer 6 can be used by programmer 7 can be used by programmer 8 The contents of the buffer can't be moved by the GC 9 Marks the contents as coming from a non-Parrot source 10 Mark the buffer as pointing to system memory 11 Mark the contents as Copy on write 12 Private flag for the GC system. Set if the buffer's in use as far as the GC's concerned 13 Mark the bufffer as needing GC 14 Mark the buffer as on the free list 15 This is a constant--don't kill it! 16 For debugging, report when this buffer gets moved around 17 Generation in the GC pools 18 Generation in the GC pools 19 Buffer header has a strstart which needs to be updated with bufstart =head3 String functions Just notes!! INTVAL string_compute_strlen(STRING *) STRING *string_concat(interpreter, STRING *, STRING *, UINTVAL) STRING *string_append(interpreter, STRING *, STRING *, UINTVAL) STRING *string_repeat(interpreter, const STRING *, UINTVAL,STRING **) STRING *string_chopn(STRING *, INTVAL) STRING *string_substr(struct Parrot_Interp *, STRING *, INTVAL, INTVAL, STRING **) STRING *string_replace(struct Parrot_Interp *, STRING *, INTVAL, INTVAL, STRING *, STRING **) INTVAL string_compare(struct Parrot_Interp *, STRING *, STRING *) INTVAL string_bool(const STRING *) const char *Parrot_string_cstring(const STRING *) STRING *string_set(struct Parrot_Interp *, STRING *, STRING *) UINTVAL string_length(const STRING *); INTVAL string_ord(const STRING *, INTVAL idx); FLOATVAL string_to_num(const STRING *); INTVAL string_to_int(const STRING *); STRING *string_from_int(struct Parrot_Interp *, INTVAL i); STRING *string_from_num(struct Parrot_Interp *, FLOATVAL f); STRING *string_grow(struct Parrot_Interp *, STRING *s, INTVAL addlen); void string_destroy(STRING *); STRING *string_make(struct Parrot_Interp *, const void *buffer, UINTVAL buflen, const ENCODING *, UINTVAL flags, const CHARTYPE *); STRING *string_copy(struct Parrot_Interp *, STRING *); STRING *string_transcode(struct Parrot_Interp *, STRING *src, const ENCODING *, const CHARTYPE *, STRING **dest_ptr); void string_init(void); INTVAL string_index(const STRING *, UINTVAL idx); const char *string_to_cstring(struct Parrot_Interp *, STRING *); =head1 Included Languages Sorry, less than just notes!! =over 4 =item * BASIC =item * cola =item * forth =item * jako =item * miniperl =item * Ruby =item * Scheme =back =head1 Other Resources =over 4 =item * Tinderbox =over 4 The tinderbox consists of two dozen or so computers running various OS and platform configurations, downloading the latest Parrot distribution every few hours and running the test suite to verify that it works on that given combination of software and hardware. To view the results of the tinderbox system, check out: http://tinderbox.perl.org/tinderbox/bdshowbuild.cgi?tree=parrot =back =item * Test Coverage Results =over 4 The Parrot test suite is intended to test all aspects of Parrot's code. You can see how successful we are at this goal by checkout the test coverage. It gives line, branch, and call coverage percentages on a per-file or per-function breakdown. Find it here: http://www.hitchhiker.org/parrot_coverage/ =back =item * Bonsai =over 4 Bonsai is a cvs tree control tool to monitor the status of cvs trees. Whenever a check in occurs, bonsai adds that person to the "hook," a list of those responsible for the current state of the tree (this should be cleared whenever we know that things are working for sure). Users can then run queries to find out who has changed what files and access their check in comments in addition to generating diffs. =item * Query http://tinderbox.perl.org/bonsai/cvsqueryform.cgi?cvsroot=/home/tinder/perlcvs&module=parrot =item * Browse http://tinderbox.perl.org/bonsai/rview.cgi?cvsroot=/home/tinder/perlcvs&dir=parrot&module=parrot =back =back =head1 FAQ =head1 Unsolved Mysteries =over 4 =item * How do you add methods to a pmc? =item * How do you call the methods in a pmc? =item * For interpreter threads will there be more than one interpreter (Parrot_new), and if so will init_world run more than once (looks like it should, but its name makes it sound like it should not)? =item * What is a register chunk, and why would I want my registers chunky? =back =cut
use lib "lib"; use Parrot::Config; #so -> .dll #ar -> lib why no dot??? # ############################################## # Global Vars $main = "test_main.c"; #where is the function main ############################################## if ($ARGV[0] eq "-d"){ #compile a dynamic linked lib $o_files = collectObjectFiles(); if (! -e "$ARGV[1]/"){ mkdir "$ARGV[1]/"; } makeSharedLib("$ARGV[1]/",$o_files); }elsif ($ARGV[0] eq "-s"){ # build static library $o_files = collectObjectFiles(); makeStaticLib("$ARGV[1]/",$o_files); }elsif ($ARGV[0] eq "-o"){ # compile to object file $o_files = collectObjectFiles(); # source compile($ARGV[1]); }elsif ($ARGV[0] eq "-liblink"){ $o_files = collectObjectFiles(); liblink($ARGV[1], $ARGV[2], $o_files); }elsif ($ARGV[0] eq "-link"){ $o_files = collectObjectFiles(); objlink($ARGV[1], $o_files); }elsif ($ARGV[0] eq "-b"){ $o_files = collectObjectFiles(); compile($ARGV[1]); objlink($ARGV[1], $o_files); }else{ print "Usage:\n"; print " Easy compiler for parrot. Do not put any file\n"; print " extentions on the filenames when issuing commands.\n"; print " It figures out extentions itself for cross platform compatability\n"; print " examples below have win32 extentions.\n"; print " ecomp.pl -b dir/test ---builds test.exe from test.c\n"; print " ecomp.pl -o dir/test ---makes test.obj from test.c\n"; print " ecomp.pl -s dir/ ---makes static libparrot.lib\n"; print " ecomp.pl -d dir/ ---makes dynamic libparrot.dll\n"; print " ecomp.pl -link dir/test ---links objects into test.exe\n"; print " ecomp.pl -liblink dir/test libdir/lib ---links with library\n"; } exit(); #link objects into executable sub objlink{ my $object = shift; my $o_files=shift; my $output = $object . $PConfig{'exe'} ; $object = $object . $PConfig{'o'} ; $o_files = $object . " " . $o_files; my $cmd = "$PConfig{link} $PConfig{ld_out}$output $PConfig{linkflags} $o_files $PConfig{libs}"; run($cmd); } #link with library sub liblink{ my $object = shift; my $lib= shift; my $output = $object . $PConfig{'exe'} ; $object = $object . $PConfig{'o'} ; my $cmd = "$PConfig{link} $PConfig{linkflags} $object $PConfig{ld_out}$output $lib$PConfig{a} $PConfig{libs}"; run($cmd); } # gets all of the pertinent object files sub collectObjectFiles{ my $o_ext = $PConfig{'o'}; my @o_files=(); push(@o_files, glob( "*$o_ext" ) ); #root objects push(@o_files, glob( "classes/*$o_ext" ) ); #pmc objects push(@o_files, glob( "encodings/*$o_ext" ) ); #encoding objects push(@o_files, glob( "chartypes/*$o_ext" ) ); #chartype objects push(@o_files, glob( "io/*$o_ext" ) ); #io objects @o_files = grep (!/test_main/ , @o_files); my $o_files = join (" " , @o_files); return $o_files; } #compile to object sub compile{ my $source = shift; my $output = $source . $PConfig{'o'}; $source = $source . ".c"; my $cmd = "$PConfig{cc} $PConfig{ccflags} -I./include -c $PConfig{cc_o_out}$output $source"; run($cmd); } #makes a static library. #Don't have the .h info yet sub makeStaticLib{ my $location = shift; my $o_files=shift; #Windows dependent see -lib below my $cmd = "$PConfig{ld} -lib $PConfig{ld_out}$location/" . "libparrot.$PConfig{ar} $o_files\n"; run($cmd); } #makes a shared library sub makeSharedLib{ my $location = shift || "."; my $o_files=shift; my $cmd = "$PConfig{ld} $PConfig{ld_shared} $PConfig{ld_shared_flags} $PConfig{ldflags} $PConfig{ld_out}$location/libparrot$PConfig{so} $o_files $PConfig{libs}\n"; run($cmd); } # Run the command and print result sub run{ my $cmd = shift; print "$cmd\n"; $out = `$cmd`; print "$out\n"; }