User Tools

Site Tools


geda:pcb_developer_introduction_2

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
geda:pcb_developer_introduction_2 [2018/01/27 19:21]
cparker
geda:pcb_developer_introduction_2 [2018/09/01 12:44] (current)
cparker [Where to Start]
Line 1: Line 1:
 +====== Getting Started as a pcb Developer =====
 This page is intended to be a less overwhelming version of the [[pcb_developer_introduction]]. This page is intended to be a less overwhelming version of the [[pcb_developer_introduction]].
  
Line 27: Line 28:
 git pull git pull
 </​code>​ </​code>​
-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 listor to LaunchPad.+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. ​You can also check here for some relevant examples: [[geda:​scm|Source Control Management]]. 
 + 
 +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 LaunchPad, or you can create and publish your own [[pcb:​plugins]] for pcb on your blog, github, whateverIf you do the later, let us know so that we can link to it!
  
 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: 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:
Line 38: Line 41:
 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 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 second thing you need to know, is that pcb is designed to work with many different HIDs (Human Interface Devices). You can read more about them here: [[pcb:​hids|pcb HIDs]]. 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 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.
Line 49: Line 52:
 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. 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: {{ :​geda:​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: 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: {{ :​geda:​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:
 <code c> <code c>
 +#include <​stdio.h>​
 +
 #include "​globalconst.h"​ #include "​globalconst.h"​
 #include "​global.h"​ // types #include "​global.h"​ // types
Line 59: Line 65:
 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. 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.+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
 <code c> <code c>
 static int static int
-plugin_action ​(int argc, char **argv, Coord x, Coord y)+myplugin_action ​(int argc, char **argv, Coord x, Coord y)
 { {
   int i = 0;   int i = 0;
Line 74: Line 80:
 } }
 </​code>​ </​code>​
-This is the entry point to the actionYour 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).+This action will print "Hello from your new plugin!" ​to the message logIf 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.
 <code c> <code c>
-static HID_Action ​plugin_action_list[] =+static HID_Action ​myplugin_action_list[] =
 { {
-  {"​PluginAction",​ NULL, plugin_action, NULL, NULL}+  {"​PluginAction",​ NULL, myplugin_action, NULL, NULL}
 }; };
 +</​code>​
  
-REGISTER_ACTIONS (plugin_action_list)+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]]. 
 +<code c> 
 +REGISTER_ACTIONS (myplugin_action_list) 
 +</​code>​
  
 +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.
 +<code c>
 void void
 pcb_plugin_init() pcb_plugin_init()
 { {
-  ​register_plugin_action_list();+  ​printf("​Loading plugin: myplugin\n"​);​ 
 +  register_myplugin_action_list();
 } }
 </​code>​ </​code>​
 +
 +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.
 +<code makefile>​
 +# where is the source tree
 +PCBSRC=${HOME}/​src/​pcb/​pcb
 +</​code>​
 +
 +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.
 +<code makefile>​
 +# where to put the compiled plugin
 +PLUGINDIR = ${HOME}/​.pcb/​plugins
 +</​code>​
 +
 +Update PLUGINNAME with the base name of your source file.
 +<code makefile>​
 +PLUGINNAME = myplugin
 +</​code>​
 +
 +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.
 +<​code>​
 +# 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
 +</​code>​
 +
 +Macs are different. Who's surprised? pcb builds on Macs. Who's surprised?!
 +<code makefile>​
 +# for linux or windows
 +CFLAGS += -shared
 +# for mac os
 +#CFLAGS += -dynamiclib -Wl,​-undefined,​dynamic_lookup
 +</​code>​
 +
 +Finally, some rules to build the shared library and install it.
 +<code makefile>​
 +${PLUGINNAME}.so:​ ${PLUGINNAME}.c
 + ${CC} ${CFLAGS} $^ -o $@
 + file $@
 +
 +install: ${PLUGINNAME}.so
 + install -m 0755 -D $^ ${PLUGINDIR}
 +
 +</​code>​
 +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 [[http://​wiki.geda-project.org/​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.1517098893.txt.gz · Last modified: 2018/01/27 19:21 by cparker