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";
}
