Showing posts with label Visual Studio. Show all posts
Showing posts with label Visual Studio. Show all posts

Monday, December 15, 2008

Visual Studio Command Line Build Troubles

You can build Visual Studio projects by the command line with the following switches

devevnv.exe /rebuild

to rebuild the entire solution. For example

devenv.exe my_solution.sln /rebuild Release

or to build a single project

devenv.exe my_solution.sln /project MyProject /rebuild Release

I've found two ways in which Visual Studio command line builds fail for solutions which otherwise build in the IDE. The first problem is the out of order build, where the project dependencies seem to be ignored, and a project is not built soon enough in the build, causing libraries to not be found. The other problem I find is Visual Studio crashing outright during a command line build.

I found today that Visual Studio allows for multiprocessor builds. These don't work in Visual Studio 2005 or 2008 command line builds, and must be disabled if you do command line builds.
  1. Select tools/options
  2. In the options dialog, select Projects and Solutions/Build and Run
  3. In the Build and Run options, set maximum number of parallel project builds to 1.
Happy coding,

The Schmitzer

Thursday, August 14, 2008

Dear Visual Studio 2008 File Save As Implementor

Did you question the requester when the aforementioned told you that Save As should remove a file from an old project? Making a copy of a file being the same as moving a file?

If it never dawned on you that this was a bad way to implement this feature, perhaps you could move to another project where usability is not such a concern.

Perhaps Windows Vista is calling you?

Love,

The Schmitzer

Tuesday, April 8, 2008

Simplest MPC File For EXEs

Here is the simplest possible mpc file for building executables:

project (simple_exe) {
exename=simple
}
This creates a project file with the following settings in Visual Studio 2005:
  • Console Application
  • No MFC
  • No ATL
  • No CLR
  • Use Program Database
  • Warning level 3
  • Multithreaded DLL C runtime
  • wcar_t treated as built-in type
  • Force for loop conformance
  • Enable RTTI
  • No Precompiled Headers
A pretty solid set of defaults. You get consitent settings on debug and release, for 3 lines of configuration. More to come.

Wednesday, March 19, 2008

Dear Visual Studio Search Team

To Whom it May Concern:

I type my search term in the search bar...

I click on the "find in files" icon...

You replace my search term with whatever the cursor happened to be pointing to...

I then search for what you want, not what I want. Don't you get it?

Love,

The Schmitzer

Tuesday, October 9, 2007

New Project Created - In Seconds

Update - Now that I am using MPC my next project was created in less than a minute. And it was done while standing up. I was in line for B group boarding a Southwest flight. And it was correct, the first time, both Debug and Release.

Can't do that with Visual Studio!

Monday, October 1, 2007

Making Good on My MPC Promise

Had to create a new project today - the first time since my promise. And yes, I did make it using MPC. It was really good to get this started.

It wasn't easy, for sure. There are a few decisions to be made and a few gotchas to avoid. With a little blogging, I should be able to help anybody who cares adopt this tool.

The Files.
MPC has four file types - I've used three of them. The file types are:

  • Project files *.mpc: The project files are used to represent build targets, including executables, static libraries, and dynamic libraries. When targeting a Visual Studio build environment, a .vcproj file will be created for each .mpc file.
  • Workspace files *.mwc: The workspace files have two purposes. First, it allows you to define where the tool should be looking for files. Second, it stands as a placeholder for a workspace for your project.
  • Project base files *.mpb: The design of MPC splits out project descriptions into two parts: how to build and to consume. The above .mpc file describes how to build a project, while the base files describe how to consume the project. This is a key distinction from Visual Studio, where the consumer of a.lib defines how to consume a.lib. These files are said to be base files and projects which use them are said to "inherit" from the base files. While this can truly be an inheritance relationship, I more often see the producer/consumer model.
  • Workspace base files *.mwb: Like project files, workspace files can use inheritance as well. The .mwb files provide this capability. This is the file type which I haven't used yet, but if you had multiple workspace files to create, this could be useful.
Decisions to be Made
When building MPC infrastructure, my philosophy is to set up MPC in order to (1) make consistency across projects easy to achieve, (2) make creating new projects as simple as possible. The first decision is where to keep your .mpb and .mwb files. Whatever the directory, indicate to the MPC scripts that it must be searched always. This is accomplished through the cmdline option in a .mwc file.

example.mwc:

workspace (example) {
cmdline += -include C:\mpc_base
}

This is a simple workspace, but shows how a simple tool with a rational set of defaults can be a powerful time saver. In this case a workspace named example will be created and include projects for all .mpc files that MPC encounters while running. Alternatively, individual .mpc files can be named. When MPC runs, if it cannot find a base file, it will also look in C:\mpc_base. Note the += operator - this is appending to the value, not overwriting, which can also be expressed.

Second, it is useful to determine how and where you will set defaults for projects. For example, do you have a common include point? Perhaps C:\svn\libs\include? Should all projects add this directory to their include path? To set defaults like this, define a project that all projects should inherit from. If your company is named xyz, I would name this project xyz_base:

xyz_base.mpb:

project (xyz_base) {
includes += C:\svn\libs\include
}
If you are groaning at the use of absolute paths, you can also indicate macros:

project (xyz_base) {
includes += $(LIB_ROOT)\include
}
This expression would not ask MPC to interpret the environment variable LIB_ROOT, but pass it on in the project files which inherit from it.

Creating Projects.
Now suppose my project consisted of a static library named calc and a executable named gui, which links in the calc library. I'll need to be able to build calc:

calc.mpc:

project (calc) : xyz_base {
staticname = calc
sharedname =
}
Calc derives from xyz, so it inherits the includes directive from it. No files are mentioned, so all source files in the .mpc file's directory will be included in the project build. Calc is defined as a static library, with output name calc. Extensions to the file name will be automatically added to indicate the debugginess and threaddedness of the library.

To consume calc, you will need a .mpb file:

calc.mpb:

project (calc) : xyz_base {
libs += calc
after += calc
libpaths += $(XYZ_ROOT)/calc
}
Here you see that consumers of calc need to link in the calc library if they are not already, and must be built after calc. Also, the consumers will know where to find the cal libraries, which would be the default, as they are not overridden in calc.mpc.

Finally, the consuming application:

gui.mpc:

project (gui) : calc, xyz_base {
exename = gui
}
When looking at this, it is easy to see how MPC can lead to productivity gains. Three lines and you have a project, working for both debug and release builds.

To build the projects, go to the project's root directory and run the mwc.pl script. This is the workspace creator, which traverses your directory structure and invokes mpc.pl for you.

perl \mpc\mwc.pl xyz.mwc -type vc8

assuming you have mpc installed in the \mpc directory. I invoked mwc, which invokes mpc.

Gotcha.
If you have not yet created your source files, MPC bails out. Older versions do this quietly, and newer versions give an error message about their being no targets. In any case, if project and workspace files are not created, this is the reason.

Its not trivial, but its well worth your time. More to come.

Wednesday, September 26, 2007

The Death Of Visual Studio Projects, Finally!

Today I created my last voluntary Visual Studio project.

That's it. I'm done. No maas. I can't go on like this.

Don't get me wrong. There is a lot to like here in Visual Studio 2005. I have worked with Visual Studio since it was called Visual C++ 1.0. The IDE, compiler, and especially the debugger has improved tremendously since then.

Debugging, has come a long way. In particular, debugging CWindow.Paint() issues on Windows 3.1 was painful. You'd set a breakpoint, fire up the app, click around, and the breakpoint would get hit. This, of course, would bring the IDE to the foreground, and overwrite your app's window, which you could not see.

What, you want to see your app? That caused another Paint() call, starting the whole thing again. Debugging became an exercise in screen real estate management with 640 by 480 pixels in play.

Nowadays, this and everything else in Visual Studio is improved, with one not-so-slight exception: The project file, and its editor.

I know they have added small gadgets, like wizards, macro support, automatic linking of dependencies, a cute popup dialog for some list editing, and the like, but its just not enough.

The Problem.
Now, I'm not talking about the annoying attempts by the IDE to modify the project file to hook it up to VSS (and the corresponding battles to unlink it). Nor am I talking about the hacks to force a symbol reference because the linker gives an errant warning. I'm not even talking about how the editor rearranges options on you every other release. Those truly stink, but they are not your every day productivity issues.

I'm talking about how long it takes to create a new project and make it correct for your solution. Too long. I'm also talking about how often a project gets checked in to source control and just isn't right, perhaps breaking the Release build, or hard-coding a directory. Too often. These are productivity killers. If you've ever led a project using Visual Studio, you know what I'm talking about. You've got better things to do with your time.

There is a lot at play making sure a project is set up correctly. There are dozens of options: C runtime libraries, include paths, and output directories. Don't forget the naming of DLL files, and their import libraries, plus the symbol definitions you were supposed to add.

Add in a few don't forgets like turning off precompiled headers, changing default optimization to mimimize size, and improving the floating point comparisons.

Then there are library dependencies, which are the worst of all. My project must link in library a.lib, which uses b.lib and forces a transitive dependency on my project. Of course, that's today. Next week, b.lib will be modified, and require c.lib, so my project, along with the dozen or so which link in a.lib and the hundred or so which link in b.lib, will have to change.

And that's just for Debug builds. For Release builds, you get to do it all over again, but change certain entries according to some not-so consistent patterns.

Finally, you need to port your code to another compiler or platform. What then?

This really stinks. We deserve better.

The Solution.
Since joining OCI, I have been introduced to an open-source product called MPC. MPC takes the responsibility for creating and updating project and solution (and make) files out of your (and your team lead's) hands and generates them for you.

MPC generates project, solution, workspace, and make files from a series of MPC files which you create and edit. The MPC system separates the concepts of building a project from consuming a project. Therefore I can describe in great detail how to build a.lib, but also automatically force consumers of a.lib to become consumers of b.lib.

MPC files can inherit from each other to do interesting things like pick up defaults for unit tests or DLLs, for example. Need to target multiple platforms or compilers? MPC takes care of it, out of the box. By default, all projects will follow a consistent rule for output directories, libraries default to DLLs, and C runtimes are Multithreaded.

Its so brilliantly simple that it angered me to not think of this myself. Take a look. This is the answer I've been looking for. More to come...