User Tools

Site Tools


geda:pcb_developer_introduction_2

This is an old revision of the document!


This page is intended to be a less overwhelming version of the pcb_developer_introduction.

Finding Information

The best resource for information on the guts of pcb is the current and past developers. Make sure that you subscribe to the geda-user mailing list. There are typically monthly code sprints on the last Sunday of the month that are held on the #geda IRC channel on irc.oftc.net/6667. Sometimes the developers are there at other times as well.

There's also no shortage of documentation. Some of it is even current! Quite a bit of documentation exists in the source code, so that's a good place to look. There's also lots of stuff on this wiki, but it's not always easy to find. Search is your friend. Here are some additional resources:

Getting to Know the pcb Sources

In order to start hacking pcb, you should be familiar with how the sources are organized, and how to build system works.

The pcb sources are managed in a git repository: http://git.geda-project.org. To download the latest sources for the first time, you can use the command:

git clone git://git.geda-project.org/pcb.git

For subsequent updates, you can change do the source directory and run

git checkout master
git pull

There's lots of accessible documentation on how to use git https://git-scm.com/documentation. However, it's really easy to figure out how to do things using Google. Note that you wont be able to contribute your changes directly to the server until you get an account set up with DJ. Ask him on the mailing list. Alternatively, you can submit your patches to the mailing list, or to LaunchPad.

Now that you have the source files, you'll want to know what's stored where. The source tree's file structure is described here: pcb_source_tree_file_structure

To build pcb, you can find instructions here: building_pcb

Where to Start

The first thing you need to know about pcb is that it's been around a long time and in the hands of many different developers, each of whom had their own style. You'll see this quite clearly as you start looking around in the code. We're trying to move towards some standardized coding conventions, but, it's a big code base and no one really has the time to sit down and go through the entire thing to make it uniform. So, we do it as we go. Another consequence of pcb's history is that each developer had different ideas about how things should be implemented. So, in general, it's not safe to assume that two things that you think ought to be similar are implemented in the same way, because it was probably two different people that implemented it. This, too, is a work in progress.

The second thing you need to know, is that pcb is designed to work with many different HIDs (Human Interface Devices). The term might be a little misleading because, for example, the gtk interface and the png exporter are both considered HIDs. Anyway, the point is that pcb is split roughly into two parts: the database and the interface. These two things aren't completely independent of each other, but, the idea is that the interface (HID) can be one of many different ways to modify or render the database. Presently we have a number of HIDs, e.g. gtk, lesstif, batch, Gerber, png, etc. The first two are actually windowing systems that allow a human to interact with the database in the kind of friendly windowed environment that users are accustomed to. The others might be better known as exporters. This separation makes it relatively easy to implement new HIDs.

The third thing you need to know, is that pcb is presently not organized around objects. pcb is organized around functions. So, instead of having a Line structure with a Move function that will change the coordinates of the line, there a structure of Move functions that is indexed by object type. This can be rather annoying for those of us that have spent our formative years learning object oriented programming, but, pcb predates that. It'll be a big project that we undertake someday, and we'd love your help. For now, this is what we've got.

The first time you open up the pcb sources can be a bit intimidating, but don't worry, this page is here to help. The first two things you'll want to know about are the data structures and “actions”. For now, the data structures are basically all stored in “global.h”. You can look through these, and many of them look as you might expect. The documentation here on the wiki is a work in progress, but you can find some data structures documented here: pcb_data_structures.

Actions are how things get done in pcb. When you click the mouse somewhere, or hit a key on the keyboard, you set of a chain of actions. Following a chain of actions can feel a little bit like trying to untangle a plate of spaghetti, but trust me, it gets easier. Understanding how actions work is essential to understanding pcb. So, it's worth it to spend some time tracing a few actions through. This really is one of the best ways to learn how pcb works. There are a couple of examples here: pcb_action_traces. Once you've run through those, it's a good idea to pick another action, like placing text on the workspace, and trace that through. Then write it up and contribute it to the wiki :) It's a good idea to actually record the sequence of function calls in a text file or something. Otherwise it'll get too tangled in your memory and you wont be able to keep things straight. Plus, trust me, you'll revisit it later when you're trying to debug something.

Your First Action

Since actions are basically everything (exaggeration), the “hello world!” of pcb development is writing your first action. You can either do this directly in the source tree, or you can do it as a plugin. The primary difference is how you compile them. They're both useful, so, we'll hit them both. Adding an action boils down to three parts: an action function, an action list, and an action list registration.

The Action Code

Let's start with the plugin method, since that doesn't require us to muck with anything in the pcb source tree. I've prepared a convenient plugin template for your coding pleasure: pcb_plugin_template.tar.gz It contains two files, a makefile and a C source file. Let's break down the meat of the source file:

#include <stdio.h>
 
#include "globalconst.h"
#include "global.h" // types
 
#include "error.h" // Message
#include "hid.h"   // REGISTER_ACTIONS

These are the includes that you need. That's basically the minimum to do anything useful. All of the types are defined in the two globals, hid include is required to be able to register actions, and the error include is where the function that prints to the message log is.

Next up, the action function. This is the entry point to the action. Your action doesn't have to be entirely contained in one function, but, when you call your action, this is the function that gets called. In this case, it's where all the action is (… yeah, I really did do that). In has a calling signature similar to that on a main function, but with the addition of a pair of coordinates. The argument vector will contain the arguments that were passed to the action (you can call actions like functions, more later). The coordinates are appended by the system (you don't explicitly add them to an action call) and could be different things depending on how the action was initiated. The Coord type is an alias for the “long” type (defined by configure through a chain of configure → config.h → globalconst.h → global.h) and its units are nano meters.

static int
myplugin_action (int argc, char **argv, Coord x, Coord y)
{
  int i = 0;
  Message("Hello from your new plugin!\n");
  if ((argc == 2) && (strcmp(argv[0], "Echo") == 0))
  {
    Message("Echoing: %s\n", argv[1]);
  }
 
  return 0;
}

This action will print “Hello from your new plugin!” to the message log. If you provided two arguments to the function and the first one is “Echo”, then it will also echo the second argument to the message log.

The Message function is useful. It will print things to the message log. You can use it with format strings just like you would use printf. So, now instead of littering your code with printfs while your debugging, you can litter it with Messages. The other thing is how to process the argument vector. Make sure you check the number of arguments to make sure you have enough of them before you start processing the contents of the vector. If you want to be clever and do it some other way, go ahead, but this is quick and easy. You can look for additional arguments by added some else ifs. It's usually a good idea to add an else clause at the end that tells what the arguments were so that when your debugging why your action isn't getting called, you can find out that it really is getting called, but you're just giving it the wrong argument. Odds are that your action isn't going to be called 1000s of times per second, so, decoding performance shouldn't be a big deal.

Next up, the action list. There are lots of these scattered throughout the pcb sources. Some contain just a few, and some contain way more than they should. The action list is an array of HID_Action structures. The structure is defined in hid.h. The HID_Action structure contains the action's name, a field indicating that coords are required, the action function, a string description of the action, and a string description of the actions calling signature. In this case we're being lazy and only providing the essentials. When you're building an action in the pcb source tree, instead of as a plugin, the calling signature and description are automatically added to the manual.

static HID_Action myplugin_action_list[] =
{
  {"PluginAction", NULL, myplugin_action, NULL, NULL}
};

Finally, we have to register our action list with pcb. There's a conveniently named macro that will do this for you: REGISTER_ACTIONS. Note that there's no semicolon at the end of the line. For now, don't worry too much about how this works. Later, after you've written a core action, you can read this: pcb_register_actions_explained.

REGISTER_ACTIONS (myplugin_action_list)

Since we're doing this as a plugin, we do have to worry just a little bit about how it works. Normally pcb will find all of the REGISTER_ACTION invocations at compile time and make sure they get processed, but, since we're writing a plugin and not recompiling all of pcb, we have to help just a little bit. REGISTER_ACTIONS will define a function called “register_whatever_the_name_of_the_argument_is”. In this case, register_plugin_action_list. When pcb loads plugins, it calls pcb_plugin_init. So, we just have use that to register our actions.

void
pcb_plugin_init()
{
  printf("Loading plugin: myplugin\n");
  register_myplugin_action_list();
}

That wasn't so bad was it? If you write another one, make sure that wherever there is a name “myplugin”, that you change it to something unique.

Building the Action Plugin

Okay, now we have to compile and install our plugin. Fortunately, the makefile in the archive you downloaded earlier will do this for you too. You do have to do a little editing though. So, lets go through that too. pcb plugins are the same as shared libraries.

In order to build a plugin, you do have to have the pcb sources, but you had those anyway because you wanted to be a pcb hacker. You'll need include files from pcb for data types and other things, so, the compiler needs to know where to find them. Set this appropriately.

# where is the source tree
PCBSRC=${HOME}/src/pcb/pcb

pcb automatically looks for plugins in a couple of places, this is one of them. Yes, pcb contributes to the .spam in your home directory. Don't change this.

# where to put the compiled plugin
PLUGINDIR = ${HOME}/.pcb/plugins

Update PLUGINNAME with the base name of your source file.

PLUGINNAME = myplugin

Depending on what you're doing, you may need to add additional compiler flags for includes and such. Hopefully you know how to do this. If you don't, there are lots of resources to help you.

# compiler to use
CC = gcc
# base compile flags
CFLAGS = -fPIC -O2 
# includes for glib
CFLAGS += `pkg-config --cflags glib-2.0`
# includes for gtk
#CFLAGS += `pkg-config --cflags gtk+-2.0`
#includes for pcb
CFLAGS += -I${PCBSRC} -I${PCBSRC}/src -DHAVE_CONFIG_H

Macs are different. Who's surprised? pcb builds on Macs. Who's surprised?!

# for linux or windows
CFLAGS += -shared
# for mac os
#CFLAGS += -dynamiclib -Wl,-undefined,dynamic_lookup

Finally, some rules to build the shared library and install it.

${PLUGINNAME}.so: ${PLUGINNAME}.c
	${CC} ${CFLAGS} $^ -o $@
	file $@
 
install: ${PLUGINNAME}.so
	install -m 0755 -D $^ ${PLUGINDIR}

So, type “make install” and it should build and install the plugin somewhere where pcb will find it.

Running Your Action

Now it's time to fire up pcb and give your new action a test run. Once pcb is open, open up the Message Log, Window → Message Log. Click back in the main window, and type “:” to bring up the command entry. This might come up in either a separate window or on the status bar depending on how your preferences are set. Type the calling signature of your new action “PluginAction()” and hit enter. You should see “Hello from your new plugin!” appear in the log. Next try “PluginAction(Echo, Hello World)”. This also tells you something about how pcb handles action arguments (hint: they're csv's).

If instead of the message we expect, you see “no action PluginAction()” then obviously something is wrong. Try running pcb from the console. When pcb loads, you should see the message “Loading plugin: myplugin”. If you don't, then clearly pcb isn't loading your plugin. This is probably because it didn't actually build or install properly. Check the contents of ~/.pcb/plugins and make sure that myplugin.so is there and that it has execute privileges.

If you do see the console message indicating that your plugin loaded, then you might have a namespace collision. It's possible for plugins to mask each others structures if they use the same names like “myplugin_action” or “myplugin_action_list”.

Congratulations, you're a pcb hacker!

Making Your Action Part of pcb

Okay, so, your shiny new action has reached a level of awesome that merits putting it directly into pcb. What now? Here's another example that does just that: pcb_adding_a_core_action.

Next Steps

There are lots and lots of projects to help with. A good way to get started is to start looking at bug reports on LaunchPad: https://launchpad.net/pcb . While you're there, you could have a look at the blueprints and milestones. We also have a running list of projects pcb-projects that you could have a look at. If you need some other ideas, send some email to the list. Happy hacking!

geda/pcb_developer_introduction_2.1517153321.txt.gz · Last modified: 2018/01/28 10:28 by cparker