Using M4RI with Visual Studio (2010)

Issue #28 resolved
Former user created an issue

I took me about three days of work to get M4RI working with VS. This could be improved.

At the root is the "non-standardness" of C. When using GCC, C programs may declare variables at any location in a block. With the Microsoft (MS) C compiler, variables must be declared at the beginning of a block. At several locations in the M4RI code you violate this requirement, for example line 87 of pls_mmpf.c:

{{{ #!c for(size_t c2=0; c2<curr_pos && start_col + c2 < A->ncols -1; c2++) }}}

The MS compiler does not allow you to declare c2 in the for loop as you can in Java or with GCC.

The solution to this problem is to change a setting in the VS project to force the MS compiler to compile the .c files as C++ code, because the MS C++ compiler does allow declarations anywhere in a block. This setting can be changed by going to the project properties -> Configuration Properties -> C/C++ -> Advanced -> Compile As -> “Compile as C++ Code (/TP)”. The major downside to this solution is that it forces the user code to be C++. Your only other option (as far as I know) is to go through and move every variable declaration to the beginning of the enclosing block.

Unfortunately, this change causes another problem. Since we are forcing the compiler to compile as C++, it automatically defines __cplusplus. In m4ri.h, this results in all of the header files (and thus all of the function definitions) to be wrapped in a extern “C” { }” environment. This results in linking errors because the functions are in fact C++ now. This can be fixed by replacing both preprocessor statements in m4ri.h from

{{{ #!c "#ifdef __cplusplus" }}}

to

{{{ #!c "#if (defined __cplusplus && !defined _MSC_VER)" }}}

(or some other macro that is defined when running VS. This definitely qualifies as a “hack”, so perhaps you can come up with a nicer solution.

Another change that must be made to the VS project is that there is no code in the m4ri source to export to a DLL, which is what the VS project is set up to create. DLLs happen to be a pain to use however, so I think it is very reasonable to use a static library (.lib) instead. This can be achieved without editing any code, but by simply changing a couple of settings. Go to project properties->Configuration Properties->General. Change “Configuration Type” to “Static library (.lib)” and change “Target Extension” to “.lib” (without quotes).

Comments (7)

  1. Martin Albrecht repo owner

    I took me about three days of work to get M4RI working with VS. This could be improved.

    Thanks a lot for that!

    At the root is the "non-standardness" of C. When using GCC, C programs may declare variables at any location in > a block. With the Microsoft (MS) C compiler, variables must be declared at the beginning of a block. At several locations in the M4RI code you violate this requirement, for example line 87 of pls_mmpf.c: for(size_t c2=0; c2<curr_pos && start_col + c2 < A->ncols -1; c2++) The MS compiler does not allow you to declare c2 in the for loop as you can in Java or with GCC.

    This is wrong. Declaring a variable this way is part of the C99 standard which the MS compiler supports. I compiled M4RI with Visual Studio before (without getting a proper library out, but it compiled).

    Another change that must be made to the VS project is that there is no code in the m4ri source to export to a DLL, > which is what the VS project is set up to create. DLLs happen to be a pain to use however, so I think it is very reasonable to use a static library (.lib) instead. This can be achieved without editing any code, but by simply changing a couple of settings. Go to project properties->Configuration Properties->General. Change “Configuration Type” to “Static library (.lib)” and change “Target Extension” to “.lib” (without quotes).

    I think this is decent intermediate solution, but we should eventually aim for producing a proper DLL. Other open-source projects managed to do this.

  2. fcairforce

    It seems M$ Visual Studio only supports C89 rather than C99. http://stackoverflow.com/questions/2706453/what-is-the-cause-of-these-visual-studio-2010-errors-warnings http://connect.microsoft.com/VisualStudio/feedback/details/526116/c99-support

    You were able to compile m4ri because "Compile as C++" was selected in your m4ri VS project. This setting was also selected on the VS project in the m4ri source. Because this option was selected, we were both able to compile m4ri to a lib/dll, but the problem in m4ri.h prevents me from *using* the library.

    On C programs in general, I am unable to declare variables anywhere besides at the beginning of a block.

  3. fcairforce

    As far as lib vs dll, I have seen lib files used in most external libraries. To me, it is not a compromise to use lib over dll, however I am not familiar with the differences.

  4. fcairforce

    To be a bit clearer, my original post should be edited as follows: The root of the problem is that the MS C compiler does not support C99. This means variables must be declared at the beginning of a block.

    I have been using VS for several years now, and it is an unfortunate limitation.

    Also, my post indicated that the "Compile as C++" options was not already set in the m4ri VS project: it was. This results in the same implications as I stated above, namely that all user code must be C++ (unless there is a way to make C code use a C++ library). Although the m4ri library compiles fine when this option is selected, users cannot link to m4ri unless the "extern C" block is removed from M4RI.h

  5. Log in to comment