Возвращаемое программой cl.exe значение
Программа cl.exe возвращает нулевое значение в случае успешного выполнения (отсутствия ошибок) и ненулевое значение во всех остальных случаях.
Возвращаемое программой cl.exe значение может использоваться при компиляции из файла скрипта, файла powershell, CMD-файла или BAT-файла. Рекомендуется перехватывать выходные данные компилятора, чтобы при необходимости использовать их для устранения возникающих ошибок или предупреждений.
В программе cl.exe предусмотрено слишком много возможных кодов ошибок завершения cl.exe, чтобы можно было их все перечислить. Код ошибки можно найти в файлах winerror.h или ntstatus.h, включенных в пакет средств разработки программного обеспечения Windows, в каталоге %ProgramFiles(x86)%\Windows Kits\version\Include\shared\. Коды ошибок, возвращенные в виде десятичного числа, для поиска необходимо преобразовать в шестнадцатеричный вид. Например, код ошибки -1073741620 преобразуется в шестнадцатеричный код 0xC00000CC. Эта ошибка найдена в ntstatus.h, где соответствующее сообщение — «Указанное имя общей папки не удается найти на удаленном сервере». Список скачиваемых кодов ошибок Windows см. в разделе [MS-ERREF] «Коды ошибок Windows».
Для выяснения значения ошибки компилятора можно также использовать программу поиска ошибок в Visual Studio. В командной оболочке Visual Studio введите errlook.exe, чтобы запустить программу; или в интегрированной среде разработки Visual Studio в строке меню выберите «Сервис«, «Поиск ошибок». Введите значение ошибки, чтобы найти связанный с ней описательный текст. Дополнительные сведения см . в справочнике по ERRLOOK.
Замечания
Ниже приведен пример BAT-файла, в котором используется значение, возвращаемое программой cl.exe.
echo off cl /W4 t.cpp @if ERRORLEVEL == 0 ( goto good ) @if ERRORLEVEL != 0 ( goto bad ) :good echo "clean compile" echo %ERRORLEVEL% goto end :bad echo "error or warning" echo %ERRORLEVEL% goto end :end
Параметры компилятора
cl.exe — это средство, которое управляет компиляторами и компоновщиками Microsoft C++ (MSVC) C++ и C++. cl.exe можно запускать только в операционных системах, поддерживающих Microsoft Visual Studio для Windows.
Это средство можно запустить только из командной строки разработчика Visual Studio. В системной командной строке или проводнике это невозможно. Дополнительные сведения см. в статье Использование набора инструментов MSVC из командной строки.
Компиляторы создают файлы общего формата файлов объектов (COFF) (OBJ). Компоновщик создает исполняемые файлы (.exe) или библиотеки динамических ссылок (DLL).
Все параметры компилятора чувствительны к регистру. Для указания параметра компилятора можно использовать косую черту ( / ) или тире ( — ).
Чтобы скомпилировать без связывания , используйте параметр /c .
Поиск параметра компилятора
Чтобы найти конкретный параметр компилятора, см. один из следующих списков:
- Параметры компилятора в алфавитном порядке
- Параметры компилятора, упорядоченные по категориям
Указание параметров компилятора
В разделе для каждого параметра компилятора описывается, как его можно задать в среде разработки. Сведения об указании параметров вне среды разработки см. в следующих статье:
- Синтаксис командной строки компилятора MSVC
- Командные файлы компилятора CL
- Переменные среды CL
Связанные средства сборки
Параметры компоновщика MSVC также влияют на создание программы.
Компилятор Visual Studio (начало работы)
Цель данной статьи осветить некоторые тонкие моменты компиляции c++ приложения компилятором Visual Studio. Все примеры будут компилироваться из командной строки (bat файлами) это позволит лучше понять происходящее. В примерах я использую Visual Studio Express 2012 for Windows Desktop.
Рассмотрим следующий простой пример консольного приложения Windows в котором печатаются все параметры, передаваемые через командную строку, и переменные окружения (envp — это указатель на массив, содержащий переменные окружения с их значениями, разделенные знаком равенства (=)):
#include #include int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) < _tprintf(TEXT("argc = %d\n"), argc); for(int i = 0; i < argc; ++i) < _tprintf(TEXT("argv[%d] = \"%s\"\n"), i, argv[i]); >int n = 0; while(envp[n] != NULL) < _tprintf(TEXT("envp[%d] = \"%s\"\n"), n, envp[n]); n++; >return 0; >
.bat файл, компилирующий этот пример, имеет вид:
set "vc_path=C:\Program Files\Microsoft Visual Studio 11.0\VC\" call "%vc_path%vcvarsall.bat" x86 set "bin=bin\" set "src=src\" set "progname=simple" "%vc_path%bin\cl.exe" /c /ZI /nologo /W3 /Od /Oy- /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" ^ /Gm /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Fo"%bin%%progname%.obj" ^ /Fd"%bin%%progname%.pdb" /Gd /TP /analyze- /errorReport:prompt %src%%progname%.cpp "%vc_path%bin\link.exe" /ERRORREPORT:PROMPT /OUT:"%bin%%progname%.exe" /INCREMENTAL /NOLOGO kernel32.lib user32.lib ^ gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib ^ odbc32.lib odbccp32.lib /MANIFEST /MANIFESTUAC:"level='asInvoker' uiAccess='false'" ^ /manifest:embed /DEBUG /PDB:"%bin%%progname%.pdb" /TLBID:1 /DYNAMICBASE /NXCOMPAT ^ /IMPLIB:"%bin%%progname%.lib" /MACHINE:X86 %bin%%progname%.obj pause
При этом предполагается следующее расположение файлов

Во всех Windows-приложениях должна быть входная функция, за реализацию которой отвечаете вы. Существует две такие функции:
int WINAPI _tWinMain( HINSTANCE hInstanceExe, HINSTANCE, PTSTR pszCmdLine, int nCmdShow); int _tmain( int argc, TCHAR *argv[], TCHAR *envp[]);
_tWinMain и _tmain это в действительности макросы, которые раскрываются как WinMain или wWinMain для _tWinMain и main или wmain для _tmain в зависимости от того используется Unicode или нет.
На самом деле входная функция операционной системой не вызывается. Вместо этого происходит обращение к стартовой функции из библиотеки C/C++, заданной во время компоновки параметром -entry: командной строки. Она инициализирует библиотеку С/С++, чтобы можно было вызывать такие функции, как malloc и free, а также обеспечивает корректное создание любых объявленных вами глобальных и статических С++-объектов до того, как начинается выполнение вашего кода. В следующей таблице показано, в каких случаях реализуются те или иные входные функции.
Типы приложений и соответствующие им входные функции
| Тип приложения | Входная функция | Стартовая функция, встраиваемая в исполняемый файл |
| GUI-приложение, работающее с ANSI-символами и строками | _tWinMain (WinMain) | WinMainCRTStartup |
| GUI-приложение, работающее с Unicode-символами и строками | _tWinMain (wWinMain) | wWinMainCRTStartup |
| CUI-приложение, работающее с ANSI-символами и строками | _tmain (main) | mainCRTStartup |
| CUI-приложение, работающее с Unicode-символами и строками | _tmain (wmain) | wmainCRTStartup |
Компоновщик отвечает за выбор подходящей стартовой функции из библиотеки С/С++ при компоновке исполняемого файла. Если задан ключ /SUBSYSTEM:WINDOWS, компоновщик ищет в коде функцию WinMain или wWinMain. Если этих функций нет, компоновщик сообщает об ошибке «unresolved external symbol». В противном случае компоновщик выбирает WinMainCRTStartup или wWinMainCRTStartup, соответственно.
Аналогичным образом, если задан ключ /SUBSYSTEM:CONSOLE, компоновщик ищет в коде функцию main или wmain и выбирает соответственно mainCRTStartup или wmainCRTStartup; если в коде нет ни main, ни wmain, сообщается о той же ошибке – «unresolved external symbol».
Но не многие знают, что в проекте можно вообще не указывать ключ /SUBSYSTEM компоновщика. Если вы так и сделаете, компоновщик будет сам определять подсистему для вашего приложения. При компоновке он проверит, какая из четырех функций ( WinMain, wWinMain, main или wmain ) присутствует в вашем коде, и на основании этого выбирет подсистему и стартовую функцию из библиотеки С/С++.
Теперь несколько замечаний по .bat файлу и ключам компилятора и компоновщика
При создании .bat файла нужно четко следить за тем, чтобы создаваемый текстовый файл имел формат завершения строки в стиле Windows или Unix, но не Mac, иначе bat файл просто не будет запускаться.
Для нормальной работы компилятора перед вызовом cl.exe или link.exe необходимо вызвать call “%vc_path%vcvarsall.bat” x86. Этот bat файл инициализирует переменные окружения INCLUDE, LIB, LIBPATH, PATH и некоторые другие необходимые для работы cl.exe и link.exe. Например, в моем случае было
set "INCLUDE=C:\Program Files\Microsoft Visual Studio 11.0\VC\INCLUDE;C:\Program Files\Windows Kits\8.0\include\shared;C:\Program Files\Windows Kits\8.0\include\um;C:\Program Files\Windows Kits\8.0\include\winrt;" set "LIB=C:\Program Files\Microsoft Visual Studio 11.0\VC\LIB;C:\Program Files\Windows Kits\8.0\lib\win8\um\x86;" set "LIBPATH=C:\Windows\Microsoft.NET\Framework\v4.0.30319;C:\Windows\Microsoft.NET\Framework\v3.5;C:\Program Files\Microsoft Visual Studio 11.0\VC\LIB;C:\Program Files\Windows Kits\8.0\References\CommonConfiguration\Neutral;C:\Program Files\Microsoft SDKs\Windows\v8.0\ExtensionSDKs\Microsoft.VCLibs\11.0\References\CommonConfiguration\neutral;"
При вызове cl.exe использовались следующие ключи:
- /с – компиляция без связывания
- /ZI – компилятор включает отладочную информацию в базу данных приложения (только для x86)
- /nologo – подавляет отображение информации о компиляторе
- /W3 – устанавливает уровень предупреждений компилятора на 3 уровень
- /Od – отключает оптимизацию (так как /Od предотвращает перемещение кода, установка этого ключа облегчает процесс отладки)
- /Oy – предотвращает создание указателей фрейма в стеке вызова, /Oy- отключает такое поведение (только для x86)
- /D “_DEBUG” – определяется при компиляции с ключами /LDd, /MDd и /MTd
- /D “_WINDOWS” – определяет, что целевая OS – Windows
- /D “UNICODE” – указывает компилятору на необходимость использовать в приложении версии Win API функций для работы с Unicode
Например, вот фрагмент из WinUser.h:
#ifdef UNICODE #define CreateWindowEx CreateWindowExW #else #define CreateWindowEx CreateWindowExA #endif
#ifdef _UNICODE #define _tcslen wcslen #else #define _tcslen strlen #endif
- инициализацию локальных переменных ненулевыми значениями. Это позволяет идентифицировать баги, которые не проявляются в отладочной сборке. Больщая вероятность, что переменная в стеке будет оставаться нулевой в отладочной сборке нежели в рилизной сборке, так как компилятор оптимизирует стек переменных в рилиной сборке. Будучи однажды использованной память отведенная под стек не обнуляется компилятором. По этому, последующие не инициализированные переменные в стеке будут содержать значения оставшееся от предыдущего использования этой области памяти.
- Проверка выхода за границы локальных переменных, таких как массивы. /RTCs не определяет выход за границы при обращении к памяти явившейся результатом выравнивания компилятором положения структуры в памяти. Такое может произойти при использовании выравнивания (С++ ), /Zp или pack или, если вы распологаете элементы структуры в таком порядке, который вынуждает компилятор вставлять отступы.
- Проверка указателя стека, что позволяет определить разрушение указателя стека. Разрушение указателя стека может произойти при несоответствии типов вызова. Например, используя указатель на функцию, вы можите вызвать функцию из DLL, которая экспортируется как __stdcall, но вы определили указатель на функцию как __cdecl.
Замечание:
стековый фрейм (функции) – область памяти, выделяемая всякий раз, когда вызывается функция, предназначается для временного хранения аргументов и локальных переменных функции.
/RTCu – заставляет компилятор выдавать предупреждения, когда переменная используется без инициализации. Например, команда, которая генерирует предупреждение (4-го уровня) С4701 может также генерировать ошибку времени выполнения при установленном ключе /RTCu. Любые команды, которые генерируют предупреждения компилятора (уровня 1 и 4) С4700, будут также генерировать ошибку времени выполнения при установленном ключе /RTCu.
Тем не менее, рассмотрим следующий фрагмент кода:
int a, *b, c; if ( 1 ) < b = &a; >c = a; // No run-time error with /RTCu
Если переменная могла быть проинициализирована, установка ключа /RTCu не приведет к предупреждению времени исполнения. В сущности, вы можете проинициализировать переменную, выполняя операцию взятия ее адреса. В последнем фрагменте кода оператор & работает как оператор присваивания. (. )
Пути для cl.exe

При использовании native-методов в яве, пришлось столкнутся с кодом на Си, а точнее компиляции dll библиотеки.
Я взял пример из учебника:
1 2 3 4 5 6 7 8
//HelloNative.c #include "HelloNative.h" #include JNIEXPORT void JNICALL Java_HelloNative_greeting(JNIEnv* env, jclass cl) { printf("Hello Native World!\n"); }
Файл HelloNative.h лежит в той же папке, что и исходник. Его содержание:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Header for class HelloNative */ #ifndef _Included_HelloNative #define _Included_HelloNative #ifdef __cplusplus extern "C" { #endif /* * Class: HelloNative * Method: greeting * Signature: ()V */ JNIEXPORT void JNICALL Java_HelloNative_greeting (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif
Как можете увидеть, там есть включаемый файл jni.h
а далее сказано следующие, в коммандной строке вписать:
cl — I jdk\include -I jdk\include\win32 -LD HelloNative.c -FeHelloNative.dll
jdk — каталог, в котором установлен пакет JDK
За эти два дня я, наверное, перепробовал все возможные варианты
Но как я не пытался, jni.h компилятор не находил. Дошло до того, что я даже переложил этот файл в папку ко всему, но никак( По родному он записан здесь:
Мой вопрос к Вам таков: что следует написать компилятору, что бы он все же скомпилировал dll?