Thursday, October 20, 2011

Add ACE Library to Windows/Linux Mechine

Thanks to Shubho Sadhu for providing this page.

These instructions assume you have a computer with Linux and Windows already installed, and a filesystem that's visible to both. My machine, for example, dual-boots Ubuntu 10.04 LTS and Windows 7, with a shared data partition. These instructions also assume you have Visual Studio 2010. If you don't, you can get it from the Engineering school's MSDNAA program, or through Dreamspark.
ACE setup is easier on the CEC machines since it's already built. Instructions that you should skip for CEC machines are highlighted in light blue.

Part A: Build and Configure ACE on Linux (one-time setup)

  1. Download ACE, version 6.0.1 (latest BFO micro release), tar+bzip2 format, from http://download.dre.vanderbilt.edu/.
  2. Follow the steps here to set up and build ACE. You can skip steps 5, 8, and 9, since we're not installing it.
  3. Add the ACE_ROOT and LD_LIBRARY_PATH environment variables to your .bashrc or .cshrc. See #1 here for an example of how to go about this.

Part B: Build and Configure ACE on Windows (one-time setup)

  1. Download ACE, version 6.0.1 (latest BFO micro release), zip format, from http://download.dre.vanderbilt.edu/.
  2. Follow the steps here to set up and build ACE using Visual Studio 2010. Steps 3, 6, 7, and 8 are skippable. The build can take a while (half an hour for me).
  3. If you haven't already, add ACE_ROOT\lib to your Windows PATH variable. On the CEC machines ACE_ROOT\lib is "\\warehouse.cec.wustl.edu\home\cec\class\cse532\ACE_wrappers_win\lib".
  4. Tell Visual Studio where to find ACE header files and libraries:
    1. Open Visual Studio 2010. If this is the first time the program's been used, choose the Visual C++ development environment if a dialog pops up.
    2. Go to File -> New -> Project...
    3. Choose Visual C++ Win32 Console Application and enter in a dummy name. (We'll delete the project later, so it doesn't matter what the name is.) Click OK, then Finish.
    4. Visual Studio has now created a dummy project for you. Go to View -> Property Manager. The Property Manager will probably appear in the upper right or upper left.
    5. Click on the small arrow to the left of the project name in the Property Manager to expand it. The Property Manager should now look something like this:
    6. Click on the small arrow to the left of "Debug | Win32" in the Property Manager to expand it.
    7. Double-click on "Microsoft.Cpp.Win32.user".
    8. Under "Common Properties", click on "VC++ Directories".
    9. In "Include Directories", add the full path for ACE_ROOT at the end (use a semicolon as a separator if needed). For example, on my machine ACE_ROOT is "C:\Program Files\ACE\ACE-6.0.1\ACE_wrappers". On the CEC machines ACE_ROOT is "\\warehouse.cec.wustl.edu\home\cec\class\cse532\ACE_wrappers_win".
    10. In "Library Directories", add the full path for ACE_ROOT\lib at the end (use a semicolon as a separator if needed). For example, on my machine ACE_ROOT\lib is "C:\Program Files\ACE\ACE-6.0.1\ACE_wrappers\lib". On the CEC machines ACE_ROOT\lib is "\\warehouse.cec.wustl.edu\home\cec\class\cse532\ACE_wrappers_win\lib". Click OK.
    11. Close Visual Studio 2010. If you get a prompt that says "One or more inherited user property sheets have not been saved. Save them now?", click Yes. Delete the dummy project. (If you don't know where the dummy project is, it's probably at Documents\Visual Studio 2010\Projects.)

Part C: Add code and set up file structure

Part C and after are setup on the project level. Follow these instructions for every lab/studio/project that you want across both OSes and IDEs.
  1. Create a folder for your lab/studio/project in the shared filesystem. In this document, the folder will be named Studio1.
  2. Create a src folder underneath the newly created project folder.
  3. Create Server and Client folders underneath the newly created src folder.
  4. Put server.cpp in the Server folder and client.cpp in the Client folder.

Part D: Project setup on Windows

  1. Open Visual Studio 2010.
  2. Go to File -> New -> Project...
  3. Choose Visual C++ Win32 Console Application. Enter Client for the Name. Type in a more descriptive name for the Solution Name. In this document, it will be WindowsStudio1.
  4. For the location, select the upper-level folder for your lab/studio/project (Studio1 in this example). Click OK.
  5. Click Next, then check Empty project. Click Finish.
  6. Go to View -> Solution Explorer. The Solution Explorer will probably appear in the upper right or upper left.
  7. In the Solution Explorer, right-click on Client, then go to Add -> Existing Item...
  8. Navigate to the src\Client directory and select client.cpp. Click Add.
  9. Go to Project -> Properties. In the dialog that opens, go to the Configuration dropdown (in the upper left) and select "All Configurations".
  10. Go to Configuration Properties -> Linker -> Input.
  11. In the Additional Dependencies field, add ace.lib to the end (use semicolons to separate if necessary). Click OK.
  12. Go to File -> Add -> New Project...
  13. Enter Server for the name, then click OK.
  14. Click Next, then check Empty project. Click Finish.
  15. In the Solution Explorer, right-click on Server, then go to Add -> Existing Item...
  16. Navigate to the src\Server directory and select server.cpp. Click Add.
  17. Go to Project -> Properties. In the dialog that opens, go to the Configuration dropdown (in the upper left) and select "All Configurations".
  18. Go to Configuration Properties -> Linker -> Input.
  19. In the Additional Dependencies field, add ace.lib to the end (use semicolons to separate if necessary). Click OK.
  20. You're ready to build! Select Build -> Rebuild Solution. Your executables will be at WindowsStudio1\Debug.

Part E: Project setup on Linux

  1. Create a directory for Linux-related project stuff underneath Studio1, for example LinuxStudio1.
  2. Download the course Makefile into the LinuxStudio1 directory.
  3. For CMPL_SRCS1, change client.cpp to ../src/Client/client.cpp.
  4. For CMPL_SRCS2, change server.cpp to ../src/Server/server.cpp.
  5. Change line 78 from
    INCFLAGS = -I/home/cec/class/cse532/ACE_wrappers
    to
    INCFLAGS = -I$(ACE_ROOT)
  6. Change line 83 from
    LIBLOCFLAGS = -L/home/cec/class/cse532/ACE_wrappers/ace -L./
    to
    LIBLOCFLAGS = -L$(ACE_ROOT)/ace -L./
  7. Save and close the Makefile.
  8. You're ready to build! Run make in the LinuxStudio1 directory. Your executables will be in the same directory (LinuxStudio1).

Random stuff

  • For the most part, you can use the same code for both Windows and Linux. However, if you run into a situation where you need different code for each, use #ifdefs. On Windows, Win32 has already been #defined, and on Linux, you can uselinux. For example: 
    #ifdef WIN32
         printf("%s", "Running on Windows\n");
    #endif /* WIN32 */
    #ifdef linux
         printf("%s", "Running on Linux\n");
    #endif /* linux */
  • At some point you might want to share code between client and server. Put the shared code in a new Shared folder under src. In Visual Studio, use Add -> Existing Item... to add each shared file to both projects. Similarly, for g++, modifyCMPL_SRCS1CMPL_SRCS2HEADER_FILES1, and HEADER_FILES2 so all shared files are compiled into both targets.

Differences between ACE on Windows vs. Linux

ACE should work with the same code for both Windows and Linux, but sometimes this isn't the case. We'll try to post such differences here when we find them.
  • In the client code, ACE_INET_Addr server(SERVER_PORT); works in Linux but not in Windows. Use ACE_INET_Addr server(SERVER_PORT, "127.0.0.1"); instead.

Sunday, October 2, 2011

GDB Quick Reference



My Tips:



1. Debug when generating new process: set follow-fork-mode <child / parent>

2. Break in to specific file: break file.cpp: <line # or function name>


3. Shortcuts: cont (continue), n (next)


4. Pass a signal to program:  (gdb) handle SIGINT pass


details:  http://www.delorie.com/gnu/docs/gdb/gdb_39.html

5.
break filename:linenum
Set a breakpoint at line linenum in source file filename.

break filename:function

Set a breakpoint at entry to function function found in file filename. Specifying a file name as well as a function name is superfluous except when multiple files contain similarly named functions.



Content below is from: http://betterexplained.com/articles/debugging-with-gdb/

Getting Started: Starting and Stopping


  • gcc -g myprogram.c
    • Compiles myprogram.c with the debugging option (-g). You still get an a.out, but it contains debugging information that lets you use variables and function names inside GDB, rather than raw memory locations (not fun).
  • gdb a.out
    • Opens GDB with file a.out, but does not run the program. You’ll see a prompt (gdb) – all examples are from this prompt.
  • r
  • r arg1 arg2
  • r < file1
    • Three ways to run “a.out”, loaded previously. You can run it directly (r), pass arguments (r arg1 arg2), or feed in a file. You will usually set breakpoints before running.
  • help
  • h breakpoints
    • List help topics (help) or get help on a specific topic (h breakpoints). GDB is well-documented.
  • q – Quit GDB

Stepping Through Code



Stepping lets you trace the path of your program, and zero in on the code that is crashing or returning invalid input.
  • l
  • l 50
  • l myfunction
    • List 10 lines of source code for current line (l), a specific line (l 50), or for a function (l myfunction).
  • next
    • Run program until next line, then pause. If the current line is a function, execute the entire function, then pause. Next is good for walking through your code quickly.
  • step
    • Run the next instruction, not line. If the current instructions is setting a variable, it is the same as next. If it’s a function, it will jump into the function, execute the first statement, then pause. Step is good for diving into the details of your code.
  • finish
    • Finish executing the current function, then pause (also called step out). Useful if you accidentally stepped into a function.

Breakpoints and Watchpoints



Breakpoints are one of the keys to debugging. They pause (break) a program when it reaches a certain location. You can examine and change variables, then resume execution. This is helpful when seeing why certain inputs fail, or testing inputs.
  • break 45
  • break myfunction
    • Set a breakpoint at line 45, or at myfunction. The program will pause when it reaches the breakpoint.
  • watch x == 3
    • Set a watchpoint, which pauses the program when a condition changes (when x == 3 changes). Watchpoints are great for certain inputs (myPtr != NULL) without having to break on every function call.
  • continue
    • Resume execution after being paused by a breakpoint/watchpoint. The program will continue until it hits the next breakpoint/watchpoint.
  • delete N
    • Delete breakpoint N (breakpoints are numbered when created).

Setting Variables and Calling Functions



Viewing and changing variables at run-time is a huge part of debugging. Try giving functions invalid inputs or running other test cases to find the root of problems. Typically, you will view/set variables when the program is paused.
  • print x
    • Print current value of variable x. Being able to use the original variable names is why the (-g) flag is needed; programs compiled regularly have this information removed.
  • set x = 3
  • set x = y
    • Set x to a set value (3) or to another variable (y)
  • call myfunction()
  • call myotherfunction(x)
  • call strlen(mystring)
    • Call user-defined or system functions. This is extremely useful, but beware calling buggy functions.
  • display x
  • undisplay x
    • Constantly display value of variable x, which is shown after every step or pause. Useful if you are constantly checking for a certain value. Use undisplay to remove the constant display.

Backtrace and Changing Frames



The stack is a list of the current function calls – it shows you where you are in the program. A framestores the details of a single function call, such as the arguments.
  • bt
    • Backtrace, aka print the current function stack to show where you are in the current program. If main calls function a(), which calls b(), which calls c(), the backtrace is
      c <= current location
      b
      a
      main
      
  • up
  • down
    • Move to the next frame up or down in the function stack. If you are in c, you can move tob or a to examine local variables.
  • return
    • Return from current function.

Crashes and Core Dumps



A “core dump” is a snapshot of memory at the instant the program crashed, typically saved in a file called “core”. GDB can read the core dump and give you the line number of the crash, the arguments that were passed, and more. This is very helpful, but remember to compile with (-g) or the core dump will be difficult to debug.
  • gdb myprogram core
    • Debug myprogram with “core” as the core dump file.
  • bt
    • Print the backtrace (function stack) at the point of the crash. Examine variables using the techniques above.

Handling Signals



Signals are messages thrown after certain events, such as a timer or error. GDB may pause when it encounters a signal; you may wish to ignore them instead.
  • handle [signalname] [action]
  • handle SIGUSR1 nostop
  • handle SIGUSR1 noprint
  • handle SIGUSR1 ignore
    • Tell GDB to ignore a certain signal (SIGUSR1) when it occurs. There are varying levels of ignoring.

Integration with Emacs



The Emacs text editor integrates well with GDB. Debugging directly inside the editor is great because you can see an entire screen of code at a time. Use M-x gdb to start a new window with GDB and learn more here.

Tips



  • I often prefer watchpoints to breakpoints. Rather than breaking on every loop and checking a variable, set a watchpoint for when the variable gets to the value you need (i == 25, ptr != null, etc.).
  • printf works well for tracing. But wrap printf in alog function for flexibility.
  • Try passing a log level with your message (1 is most important, 3 is least). You can tweak your log function to send email on critical errors, log to a file, etc.
  • Code speaks, so here it is. Use #define LOG_LEVEL LOG_WARN to display warnings and above. Use #define LOG_LEVEL LOG_NONE to turn off debugging.
    
    #include <stdio.h>
    
    #define LOG_NONE 0
    #define LOG_ERROR 1
    #define LOG_WARN 2
    #define LOG_INFO 3
    #define LOG_LEVEL LOG_WARN 
    
    
    // shows msg if allowed by LOG_LEVEL
    int log(char *msg, int level){
      if (LOG_LEVEL >= level){
        printf("LOG %d: %s\n", level, msg);
        // could also log to file
      }
    
      return 0;
    }
    
    int main(int argc, char** argv){
      printf("Hi there!\n");
    
      log("Really bad error!", LOG_ERROR);
      log("Warning, not so serious.", LOG_WARN);
      log("Just some info, not that important.", LOG_INFO);
    
      return 0;
    }
    
    
  • Spend the time to learn GDB (or another debugging tool)! I know, it’s like telling people to eat their vegetables, but it really is good for you – you’ll thank me later.