Using NCSL DAQ Software to Readout a CAEN V785 Peak-Sensing ADC Timothy Hoagland Ron Fox
Using NCSL DAQ Software to Readout a CAEN V785 Peak-Sensing ADC by Timothy Hoagland by Ron Fox Revision History Revision 1.0 December 2, 2004 Revised by: TH Original Release Revision 1.
Table of Contents Preface ........................................................................................................................................................v 1. The electronics .......................................................................................................................................1 1.1. A minimal Electronics Setup ......................................................................................................1 2. Setting up the software ............
List of Figures 1-1. A simple electronics setup for the CAEN V785 ..................................................................................1 1-2. Pulser Output Signal.............................................................................................................................2 1-3. Amplifier Output SIgnal .......................................................................................................................3 1-4. Amplified Signal with Logic pulse......................
Preface This paper’s purpose is to guide the reader in setting up and reading out data from a CAEN V785 peak sensing ADC. It covers the electronics that will be needed and how to set them up. It will show how to modify the production readout (V8.1), and SpecTcl (V3.1) software skeletons to readout and histogram data from the adc. Testing for the code is also covered to a limited extent. This paper assumes that you are • Somewhat familiar with Linux.
Chapter 1. The electronics The CAEN V785 is a 12 bit, 32-channel analog to digital converter that returns a value related to the maximum voltage that occurs during the time a gate is present. The input signal must be positive and less than 4V. The V785 is a VME based module. For a complete understanding of the module I suggest that you obtain a copy of the product manual, available as a PDF at http://www.caen.it/ 1.1.
Chapter 1. The electronics Figure 1-1. A simple electronics setup for the CAEN V785 Before starting be sure that you can secure all of these items, many are available through the NSCL electronics pool. Figure 1-1 shows the complete setup of the system, due to the varying amount of familiarity of readers to the electronics, a brief description of the component and what the signal coming out of it should look like will be given. We will first look at the signal from the pulser.
Chapter 1. The electronics Figure 1-2. Pulser Output Signal Figure 1-3. Amplifier Output SIgnal After you are happy with the signal from the amplifier plug the bipolar output into the splitter. The splitter will simply split the signal much like a "T" but will keep the 50Ω termination needed by the pulser. One of the splitter outputs will go into a LEMO to Ribbon Cable con- verter. This can be either a NIM based module or a freestanding adapter.
Chapter 1. The electronics The other output from the splitter will go into a discriminator. This could be either a leading edge or a constant fraction discriminator. The job of the discriminator is determine when a signal has occurred and to put out a logic signal when it does. The discriminator will have a threshold knob, be sure that the threshold is set above any background noise that may be present so that the discriminator only trips on the pulser signal.
Chapter 1. The electronics Figure 1-5. Amplified Signal and Gate The second output of the discriminator will go to a second gate and delay channel; this combined with the CAEN V262 will trigger the computer when there is data on the V785. This channel will be run in latched mode meaning that it will be given both a start and a stop signal for the gate. The output signal will start being "true" when the start signal is received and stops being "true" when the stop signal is received.
Chapter 2. Setting up the software The software modifications needed to make the above setup work can be divided into three tasks: 1. Telling the software what electronics we are using. 2. Telling the software how to respond to event triggers. 3. Telling the software how to analyze the data acquired. 2.1. Readout software In order to tell the software about our electronics we are going to develop a C++ class for our module.
Chapter 2. Setting up the software Tim Hoagland 11/3/04 s04.thoagland@wittenberg.edu */ #ifndef __MYEVENTSEGMENT_H #define __MTEVENTSEGMENT_H #ifdef HAVE_STD_NAMESPACE using namespace std; #endif #include #include #include #include
Chapter 2. Setting up the software __MYEVENTSEGMENT_H is not defined, and the #ifndef is true. This causes __MYEVENTSEGMENT_H to be defined, which prevents subsequent inclusions from doing anything. Ë Newer compilers define many of the standard classes, functions and constants inside of the std:: namespace. The spectrodaq.h header refers to these without explicitly qualifying them with the namespace. If the std:: namespace exists, this directive asks the compiler to search it for unqualified names (e.
Chapter 2. Setting up the software Example 2-2. Implementation of CMyEventSegment /* This software is Copyright by the Board of Trustees of Michigan State University (c) Copyright 2005. You may use this software under the terms of the GNU public license (GPL). The terms of this license are described at: http://www.gnu.org/licenses/gpl.txt Author: Ron Fox NSCL Michigan State University East Lansing, MI 48824-1321 */ /* This is class.
Chapter 2. Setting up the software string(pPacketVersion)) // ➍ { module = new CAENcard(slot); } // Destructor: MyEventSegment::~MyEventSegment() { delete module; } // ➎ // ➏ // Is called right after the module is created. // should be done now.
Chapter 2. Setting up the software // Reads data into the Packet rBuf= m_MyPacket.End(rBuf); // (12) // Closes the open Packet } return rBuf; // (13) } Ê The lines beginning with the include of config.h aneending with the #endif near here are boilerplate that is required for all implementation (.cpp) files for Readout skeletons at version 8.0 and later.
Chapter 2. Setting up the software (13) a "pointer" to the next free spot in the buffer is returned to the caller. The numbers below refer to the circled numbers in the example above. 2.1.2. Integrating your event segment with Readout Once you have created one or more event segments, you must register them with the Readout software.
Chapter 2. Setting up the software Modify it so that it reads: Objects=Skeleton.o MyEventSegment.o Save this edit, exit the editor and type: make This will attempt to compile your readout software into an executable program called Readout. If the make command fails, fix the compilation errors indicated by it and retry until you get an error free compilation. 2.1.4.
Chapter 2. Setting up the software To start the simple buffer dump program, therefore, log on to the system connected to the VME crate in which your CAEN V785 has been installed and type: spdaqxx> /usr/opt/daq/current/bin/bufdump Output similar to the following should be printed: bufdump version 2.
Chapter 2. Setting up the software The Readout program you have built runs an extended Tcl interpreter. Tcl is a scripting language that is widely used throughout the NSCL as an extension language. It provides a common base language for programming applications. Each program in turn extends this language with a set of commands that allow you to control the application itself. The commands we will be working with are: begin Begins a run.
Chapter 2. Setting up the software Focus on the section below the word Event:. This is a hexadecimal representation of the data in the first event of the buffer. The event that we made starts with 47, this is the total number of words (in hex) that exist in the event. The size of the event is filled in by the Readout framework. The next word is the number of words in our packet (in hex). This word is filled in by our documented packet.
Chapter 2. Setting up the software cd ~/experiment/spectcl cp /usr/opt/spectcl/current/Skel/* . 2.2.2. How to modify the skeleton to unpack events. SpecTcl relies on a logical pipeline of event processors to unpack data from the raw event into parameters. Each event processor has access to the raw event, and an output array-like object. This provides each event processor with access to the raw event and any data unpacked by event processors that are ahead of it in the pipeline.
Chapter 2.
Chapter 2. Setting up the software Í As previously mentioned, our event processor class must be derived from a CEventProcessor. This class definition does that. Ï The TreeParameter package provides both individual parameters (CTreeParameter), and arrays of parameters, (CTreeParameterArray). In this application we will create a CTreeParameterArray that will have one element for each channel of the CAEN V785. This data member will be a reference to that array.
Chapter 2. Setting up the software classes derived from CEventProcessor is expected to process the raw event, and already unpacked data producing new unpacked data. The event processor should return a kfTRUE if it succeeded well enough that the event pipeline can continue to run or kfFALSE if SpecTcl should abort the event pipeline and not histogram the event.
Chapter 2. Setting up the software return (high << 16) | low; } MyEventProcessor::MyEventProcessor(int ourId, int ourSlot, const char* baseParameterName) : m_rawData(*(new CTreeParameterArray(string(baseParameterName), 4096, 0.0, 4095.
Chapter 2.
Chapter 2. Setting up the software Ì The CAnalyzer reference that will be passed in to the operator() member function is really a reference to a CTclAnalyzer. Since we will be calling member functions of CTclAnalyzer directly, we must include the header of that class as well Í This section of code defines sevaral constants that help us unpack data longwords from the CAEN V785 ADC. See the hardware manual for that module for a detailed description of the format of the buffer produced by this module.
Chapter 2. Setting up the software CAEN_CHANNELMASK and CAEN_CHANNELSHIFT These two values are used to extract the channel number of a conversion from a conversion word (type CAEN_DATA). The code below shows how to do this: unsigned long channelNumber = (datum & CAEN_CHANNELMASK) >> CAEN_CHANNELSHIFT; CAEN_DATAMASK CAEN_DATAMASK can be used to extract the conversion value from an adc conversion longword (longword with type CAEN_DATA).
Chapter 2. Setting up the software found that catch block’s code is executed. If not found, the program aborts. This block allows us to catch errors from the unpackEvent function and turn them into pipeline aborts. (12) If the event we are unpacking contains the packet our processor has been told to match, unpackPacket is called to unpack the body of our packet into m_rawData. (13) If unpackPacket fails a sanity test it will throw a string exception.
Chapter 2. Setting up the software #include "MyEventProcessor.h" This makes the definition of the event processor we created known to this module. Locate the code that creates the analysis pipeline. In the unmodified MySpecTclApp.
Chapter 2. Setting up the software Now type: make to build the program. This should result in an executable file called SpecTcl. 2.2.4. Setting up SpecTcl Spectra Run the version of SpecTcl you created. Four windows should pop up: Xamine Is a window that allows you to view and interact with the spectra that SpecTcl is histogramming. TkCon This is a command console that is modified from the work of Jeffrey Hobbs currently at ActiveState. You can type arbitrary Tcl/Tk and SpecTcl commands at this console.
Chapter 2. Setting up the software Figure 2-1. The GUI window as it first appears. This shows a screenshot of the GUI just after it starts. Each top level folder contains or will contains the set of objects named by the folder. The Spectra folder will contain spectra. Folders that have a + to the left of them already contain objects. Since we did not delete the example tree parameters and variables in MySpecTclApp.cpp TreeVariable objects already exist.
Chapter 2. Setting up the software Figure 2-2. The Gui with folders open to show parameter array elements You can use the scrollbar at the right of the window to scroll up and down the through the list of parameters. You can also resize the window to make more parameters show simultaneously. We will now use the Spectra folder context menu to create an array of spectra, one for each of the parameters in the array mydetectors.caenv785. Every folder has a context menu, as do most objects.
Chapter 2. Setting up the software Figure 2-3. The Spectrum creation dialog box This dialog has several controls. The button labelled Spectrum Type accesses a pull down menu of spectrum type choices. The entry next to the label Spectrum Name: provides a space to type in the name of the spectrum. The Array? checkbutton is an idea from the original Tree Parameter Gui by Dr. Bazin.
Chapter 2. Setting up the software Figure 2-4. 1-d Spectrum editor. The left half of this editor is just the SpecTcl object browser restricted to display only the set of objects that are relevant to constructing spectra, the parameters and the gates. A parameter is required, a gate is optional. Open the Parameters folder to display the mydetectors.caenv785 parameter array. The double click on any parameter from that array, say mydetectors.canv785.00.
Chapter 2. Setting up the software Figure 2-5. Created Spectra. While this is not hard to do, it is annoying to have to do this each time we start SpecTcl. We will therefore save the current set of definitions in a definition file. On the GUI click the File−→Save Menu entry. A file choice dialog will pop up. Type myspectra in its File name: entry and click Save.... From now on, whenever you start SpecTcl, you can load these definitions, by clicking the File−→Restore...
Chapter 2. Setting up the software Figure 2-6. Initial Xamine Window The top part of the Xamine window has a menubar. The large central section has can be subdivided into panes. One (or more in the case of compatible 1-d) spectrum can be loaded into each pane. Below the spectrum display area is a status bar. The status bar will display information about the mouse pointer when it is located in a pane that has been loaded with a spectrum.
Chapter 2. Setting up the software • Save the resulting configuration file as a window definition file so that it can be loaded again next time SpecTcl is run. Locate the button in the left most box of buttons at the bottom of the screen labeled Geometry and click on it. This brings up the following dialog box: Figure 2-7. The Pane Geometry dialog Click the 4 button in the left column labeled Rows. Click the 8 button in the right column labeled Columns. Click the Ok button at the bottom of he dialog.
Chapter 2. Setting up the software Lets load the spectrum mydetectors.caenv785.00 into the upper left pane. Click on the upper left pane to select it. Click the Display button. This brings up the spectrum choice dialog shown below: Figure 2-8. Spectrum Choice dialog The Xamine title for a spectrum includes additional information about the spectrum. The leftmost part of the title, however is the spectrum name. Double click the top most entry [1] MYDETECTORS.CAENV785.00 : 1 [0, 4095 : 4096] {MYDETECTORS.
Chapter 2. Setting up the software • The selected pane is loaded with the spectrum you selected. • The selection advances to the next pane. You can finish loading the panes by hitting the down arrow key to select the next spectrum and hitting enter. Repeat as needed to fill all the panes. When all panes are full, click the Cancel button to dismiss the dialog. Now click on the Window−→Write Configuration... menu selection. This will bring up a file selection dialog box.
Chapter 3. Testing and Running the Software. Now let’s put all the pieces together and test the system end-to-end. We will: • Start SpecTcl • Reload our spectrum and window definition files into SpecTcl • Connect SpecTcl to the online system so that it will analyze data taken from our Readout program. • Start the Readout Program • Start a run in Readout • Check that we see counts in our spectra in SpecTcl First lets start SpecTcl and recover the definitions we made earlier.
Chapter 3. Testing and Running the Software. Now we must start Readout and begin a run so there is data for SpecTcl to analyze. With our current working directory set to cd ~/experiment/readout, start the readout program: ./Readout. When you get the prompt, type: begin. The status line at the bottom of the SpecTcl GUI should reflect the number of buffers SpecTcl has analyzed and the analysis efficiency. SpecTcl is not allowed to dictate the data rate.
Chapter 4. More information If you are preparing a system that will be used many times, you may want to automate the startup as well as run the Readout software under the control of a Readout Gui called ReadoutShell. Normally this automation is done by: • Writing scripts to start each of the components of the system. • Attaching these scripts to icons on a KDE desktop. It is a good idea to get all of your software debugged first, as debugging programs run under desktop icons can be challenging. 4.1.
Chapter 4. More information Refer to the numbers in the listing above when reading the annotations below: Ê Since icons may or may not source the various bash startup scripts we explicitly source the system wide and our login specific startup scripts. Ë We set the working directly explicitly to the directory in which we have installed our SpecTcl. This ensures that when SpecTcl is started, it will find its initialization scripts. Ì This starts SpecTcl, setting its standard input to the file setup.
Chapter 4. More information Ë The sbind command here binds all of the spectra into the Xamine visualization program. SpecTcl spectra need not be visible to Xamine, this command ensures they will be. Ì Unless told to do so, the GUI’s object browser will not reflect definitions that have been made outside the gui. This command tells the gui’s object browser (widget .gui.b), to rebuild the object tree.
Chapter 4. More information specified by the DAQHOST environment variable, if it is defined, or localhost if not. Consider the following script: Example 4-3. Starting ReadoutShell ~/bin/startreadout #!/bin/bash . /etc/profile . ~/.bashrc if test "$DAQHOST" == "" then host=‘hostname‘ else host="$DAQHOST" fi # ➊ /usr/opt/daq/8.1/bin/ReadoutShell -host=$host \ -path=$HOME/experiment/readout/Readout # ➋ Ê This shell script code checks to see if the environment variable DAQHOST is undefined or blank.
Chapter 4. More information 4.3. Creating desktop icons This section is specific to the KDE desktop manager. If you have chosen to use a different desktop manager for your experiment, you will need to figure out how to establish desktop shortcuts on your own. Creating a desktop shortcut on KDE 1. Login to a Linux desktop in the DAQ network. This could be an spdaq system or it could be a data-U system. Login using the user name and password for the account under which you will want the shortcut defined.
Chapter 5. Complete program listings. 5.1. Readout Software This section contains the files that make up the Readout software in their entirety. We include the Makefiles and scripts as well as the C++ source code. This software is also available online at http://docs.nscl.msu.edu/daq/samples/CAENV785/CAENV785.zip Example 5-1. MyEventSegment.h /* This is the header file to define the MyEventSegment class, which is derived from CEventSegment.
Chapter 5. Complete program listings. // One time Module setup virtual void Clear(); // Resets data buffer // co:mysegclear virtual unsigned int MaxSize(); // co:mysegobsoletemaxsize virtual DAQWordBufferPtr& Read(DAQWordBufferPtr& rBuf); // Reads data buffer }; #endif // co:mysegread Example 5-2. MyEventSegment.cpp /* This software is Copyright by the Board of Trustees of Michigan State University (c) Copyright 2005. You may use this software under the terms of the GNU public license (GPL).
Chapter 5. Complete program listings. using namespace std; #endif #include "MyEventSegment.h" // co:myheader static char* pPacketVersion = "1.0"; // co:packetversion // Packet version -should be changed whenever major changes are made // to the packet structure.
Chapter 5. Complete program listings. // Loop waits for data to become ready { if(module->dataPresent()) // If data is ready stop looping { break; } } if(module->dataPresent()) // Tests again that data is ready { rBuf = m_MyPacket.Begin(rBuf); // co:openpacket // Opens a new Packet module->readEvent(rBuf); // co:readdata // Reads data into the Packet rBuf= m_MyPacket.End(rBuf); // co:closepacket // Closes the open Packet } return rBuf; // co:returnpointer } Example 5-3. Skeleton.
Chapter 5. Complete program listings. Modified to be an 8.1 example Ron Fox 3/28/2006 fox@nscl.msu.edu */ static const char* Copyright = "(C) Copyright Michigan State University 2002, All rights res // // // // // This file contains a test readout system.
Chapter 5. Complete program listings. } virtual ~CMyExperiment() { } // Copy construction, assignment and comparison // make no sense and are therefore disallowed: private: CMyExperiment(const CMyExperiment& rhs); CMyExperiment& operator=(const CMyExperiment& rhs); int operator==(const CMyExperiment& rhs); int operator!=(const CMyExperiment& rhs); public: // The member functions below allow us to override/extend base // class behavior for experiment specific stuff.
Chapter 5. Complete program listings. \param rExperiment - CExperiment& - A reference to the experiment object that runs the readout. You will normall calls to CExperiment::AddEventSegment to register your own event segments in the experiment readout */ void CMyExperiment::SetupReadout(CExperiment& rExperiment) // co:setupreadout { CReadoutMain::SetupReadout(rExperiment); rExperiment.
Chapter 5. Complete program listings. create at the command line using the runvar command. \param rExperiment - CExperiment& the experiment object. \param rStartup - CInterpreterStartup& the interpreter startup object. \param rCore - CInterpreterCore& the core TCL interpreter add on functionality. Normally you will obtain the run variable command object and do CRunVariableCommand::Create calls to add your run variables. \note The base class creates key run variables.
Chapter 5. Complete program listings. CInterpreterStartup& rStartup, CInterpreterCore& rCore) { CReadoutMain::SetupStateVariables(rExperiment, rStartup, rCore); CStateVariableCommand& rCommand(*(rCore.getStateVariables())); // Insert your code below this comment. // state variable command object. Note that rCommand is the } /*! Add user written commands in this function.
Chapter 5. Complete program listings. # # Below, define any additional C++ compilation switches you might need. # # If you are using camac you will need to add at least: # -DCESCAMAC # or -DVC32CAMAC # to select between the CES 8210 and WIENER CAMAC interface modules. # respectively. # USERCXXFLAGS= # # Below, define any additional C compilation switches you may need.
Chapter 5. Complete program listings. # DO NOT DELETE MyEventSegment.o: MyEventSegment.h Skeleton.o: MyEventSegment.h Example 5-5. startreadout script #!/bin/bash . /etc/profile . ~/.bashrc if test "$DAQHOST" == "" then host=‘hostname‘ else host="$DAQHOST" fi # co:host /usr/opt/daq/8.1/bin/ReadoutShell -host=$host \ -path=$HOME/experiment/readout/Readout # co:startrdo 5.2. SpecTcl software Example 5-6. MyEventProcessor.
Chapter 5. Complete program listings.
Chapter 5. Complete program listings.
Chapter 5. Complete program listings. unpackPacket(p); // co:invokeUnpack } catch(string msg) { cerr << "Error Unpacking packet " << hex << nId << dec << " " << msg << endl; return kfFALSE; // co:handleError } catch(...
Chapter 5. Complete program listings. Example 5-8. MySpecTclApp.cpp static const char* Copyright = "(C) Copyright Michigan State University 2008, All rights res // Class: CMySpecTclApp ////////////////////////// FILE_NAME.cpp /////////////////////////////////////////////////// #include #include "MySpecTclApp.h" #include "EventProcessor.h" #include "TCLAnalyzer.h" #include #include #include "MyEventProcessor.
Chapter 5. Complete program listings. CTreeVariable& w2; CTreeVariableArray& unused; } MyParameters; // Similarly, having declared the structure, we must define // it and construct its elements MyParameters vars = { *(new CTreeVariable("vars.w1", 1.0, "arb/chan")), *(new CTreeVariable("vars.w2", 1.0, "arb/chan")), *(new CTreeVariableArray("vars.unused", 0.0, "furl/fort", 10, 0)) }; // CFixedEventUnpacker - Unpacks a fixed format event into // a sequential set of parameters.
Chapter 5. Complete program listings. param++; } return kfTRUE; // kfFALSE would abort pipeline. } // CAddFirst2 - Sample unpacker which adds a pair of unpacked parameters // together to get a new parameter. class CAddFirst2 : public CEventProcessor { public: virtual Bool_t operator()(const Address_t pEvent, CEvent& rEvent, CAnalyzer& rAnalyzer, CBufferDecoder& rDecoder); }; Bool_t CAddFirst2::operator()(const Address_t pEvent, CEvent& rEvent, CAnalyzer& rAnalyzer, CBufferDecoder& rDecoder) { event.
Chapter 5. Complete program listings. // // // // // // // // // // // // // // // // // // // At compile time, define: WITHF77UNPACKER and F77NPARAMS to be the maximum number of parameters the Fortran unpacker will fill in. In the unpacker, set FPARAMETERS(i) if i has been unpacked from the event. PARAMETERS are copied from 1 -> NUSED into parameters numbered NOFFSET -> NUSED+NOFFSET NOFFSET starts from zero. The fortran program should be compiled: cpp -DF77NPARAMS=nnnn yourprog.f > yourprog.
Chapter 5. Complete program listings. UShort_t* pSize = (UShort_t*)pEvent; CTclAnalyzer& rAna((CTclAnalyzer&)rAnalyzer); rAna.SetEventSize( (*pSize)* sizeof(UShort_t)); } return result; } CFortranUnpacker legacyunpacker; #endif // Function: // void CreateAnalysisPipeline(CAnalyzer& rAnalyzer) // Operation Type: // Override /* Purpose: Sets up an analysis pipeline. This function is required and must be filled in by the SpecTcl user.
Chapter 5. Complete program listings. // Function: // void BindTCLVariables(CTCLInterpreter& rInterp) // Operation Type: // override /* Purpose: Add code to this function to bind any TCL variable to the SpecTcl interpreter. Note that at this time, variables have not yet been necessarily created so you can do Set but not necessarily Get operations.
Chapter 5. Complete program listings. update program default values. */ void CMySpecTclApp::SetLimits() { CTclGrammerApp::SetLimits(); } // Function: // void CreateHistogrammer() // Operation Type: // Override /* Purpose: Creates the histogramming data sink. If you want to override this in general you probably won’t make use of the actual base class function. You might, however extend this by defining a base set of parameters and histograms from within the program.
Chapter 5. Complete program listings. present, SpecTcl must have a data source of some sort connected to it... The default test data source produces a fixed length event where all parameters are selected from a gaussian distribution. If you can figure out how to do it, you can setup your own data source... as long as you don’t start analysis, the default one is harmless.
Chapter 5. Complete program listings. // Function: // void AddCommands(CTCLInterpreter& rInterp) // Operation Type: // Override /* Purpose: This function adds commands to extend Tcl/Tk/SpecTcl. The base class function registers the standard SpecTcl command packages. Your commands can be registered at this point. Do not remove the sample code or the SpecTcl commands will not get registered.
Chapter 5. Complete program listings. */ void CMySpecTclApp::SourceFunctionalScripts(CTCLInterpreter& rInterp) { CTclGrammerApp::SourceFunctionalScripts(rInterp); } // Function: // int operator()() // Operation Type: // Override. /* Purpose: Entered at Tcl/Tk initialization time (think of this as the entry point of the SpecTcl program). The base class default implementation calls the member functions of this class in an appropriate order.
Chapter 5. Complete program listings. USERLDFLAGS= # # # Append your objects to the definitions below: OBJECTS=MySpecTclApp.o MyEventProcessor.o # # # Finally the makefile targets. SpecTcl: $(OBJECTS) $(CXXLD) -o SpecTcl $(OBJECTS) $(USERLDFLAGS) \ $(LDFLAGS) clean: rm -f $(OBJECTS) SpecTcl depend: makedepend $(USERCXXFLAGS) *.cpp *.c help: echo "make echo "make clean echo "make depend - Build customized SpecTcl" - Remove objects from previous builds" - Add dependencies to the Makefile.
Chapter 5. Complete program listings.