Bazel C++ precompiled headers implementation - c++
I have written an MSVC Precompiled Header Files (PCH) implementation for Bazel (2.0) and would like to get some feedback on it as I'm not happy with it.
To quickly recap what needs to be done to get PCH working in MSVC:
Compile the PCH with /Yc and /Fp to obtain the (1) .pch file and the (2) .obj file.
Compile the binary using the /Yu on (1) and again the same /Fp option.
Link the binary using the .obj file (2).
Implementation
We define a rule which takes the pchsrc (for /Yc) and pchhdr (for /Fp) as an argument as well as some of the cc_* rule arguments (to get the defines and includes). We then invoke the compiler to obtain the the PCH (mainly following the approach demonstrated here). Once we have the PCH, we propagate the location and linker inputs via CcInfo and the user needs to call cc_pch_copts to get the /Yu and /Fp options.
pch.bzl
load("#rules_cc//cc:action_names.bzl", "ACTION_NAMES")
load("#rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain")
def cc_pch_copts(pchheader, pchtarget):
return [
"/Yu\"" + pchheader + "\"",
"/Fp\"$(location :" + pchtarget + ")\""
]
def _cc_pch(ctx):
""" Create a precompiled header """
cc_toolchain = find_cc_toolchain(ctx)
source_file = ctx.file.pchsrc
pch_file = ctx.outputs.pch
pch_obj_file = ctx.outputs.obj
# Obtain the includes of the dependencies
cc_infos = []
for dep in ctx.attr.deps:
if CcInfo in dep:
cc_infos.append(dep[CcInfo])
deps_cc_info = cc_common.merge_cc_infos(cc_infos=cc_infos)
# Flags to create the pch
pch_flags = [
"/Fp" + pch_file.path,
"/Yc" + ctx.attr.pchhdr,
]
# Prepare the compiler
feature_configuration = cc_common.configure_features(
ctx = ctx,
cc_toolchain = cc_toolchain,
requested_features = ctx.features,
unsupported_features = ctx.disabled_features,
)
cc_compiler_path = cc_common.get_tool_for_action(
feature_configuration = feature_configuration,
action_name = ACTION_NAMES.cpp_compile,
)
deps_ctx = deps_cc_info.compilation_context
cc_compile_variables = cc_common.create_compile_variables(
feature_configuration = feature_configuration,
cc_toolchain = cc_toolchain,
user_compile_flags = ctx.fragments.cpp.copts + ctx.fragments.cpp.cxxopts + pch_flags + ctx.attr.copts,
source_file = source_file.path,
output_file = pch_obj_file.path,
preprocessor_defines = depset(deps_ctx.defines.to_list() + deps_ctx.local_defines.to_list() + ctx.attr.defines + ctx.attr.local_defines),
include_directories = deps_ctx.includes,
quote_include_directories = deps_ctx.quote_includes,
system_include_directories = depset(["."] + deps_ctx.system_includes.to_list()),
framework_include_directories = deps_ctx.framework_includes,
)
env = cc_common.get_environment_variables(
feature_configuration = feature_configuration,
action_name = ACTION_NAMES.cpp_compile,
variables = cc_compile_variables,
)
command_line = cc_common.get_memory_inefficient_command_line(
feature_configuration = feature_configuration,
action_name = ACTION_NAMES.cpp_compile,
variables = cc_compile_variables,
)
args = ctx.actions.args()
for cmd in command_line:
if cmd == "/showIncludes":
continue
args.add(cmd)
# Invoke the compiler
ctx.actions.run(
executable = cc_compiler_path,
arguments = [args],
env = env,
inputs = depset(
items = [source_file],
transitive = [cc_toolchain.all_files],
),
outputs = [pch_file, pch_obj_file],
progress_message = "Generating precompiled header {}".format(ctx.attr.pchhdr),
)
return [
DefaultInfo(files = depset(items = [pch_file])),
CcInfo(
compilation_context=cc_common.create_compilation_context(
includes=depset([pch_file.dirname]),
headers=depset([pch_file]),
),
linking_context=cc_common.create_linking_context(
user_link_flags = [pch_obj_file.path]
)
)
]
cc_pch = rule(
implementation = _cc_pch,
attrs = {
"pchsrc": attr.label(allow_single_file=True, mandatory=True),
"pchhdr": attr.string(mandatory=True),
"copts": attr.string_list(),
"local_defines": attr.string_list(),
"defines": attr.string_list(),
"deps": attr.label_list(allow_files = True),
"_cc_toolchain": attr.label(default = Label("#bazel_tools//tools/cpp:current_cc_toolchain")),
},
toolchains = ["#bazel_tools//tools/cpp:toolchain_type"],
fragments = ["cpp"],
outputs = {
"pch": "%{pchsrc}.pch",
"obj": "%{pchsrc}.pch.obj"
},
provides = [CcInfo],
)
We would use it:
BUILD.bzl
load(":pch.bzl", "cc_pch", "cc_pch_copts")
load("#rules_cc//cc:defs.bzl", "cc_binary")
def my_cc_binary(name, pchhdr, pchsrc, **kwargs):
pchtarget = name + "_pch"
cc_pch(
name = pchtarget,
pchsrc = pchsrc,
pchhdr = pchhdr,
defines = kwargs.get("defines", []),
deps = kwargs.get("deps", []),
local_defines = kwargs.get("local_defines", []),
copts = kwargs.get("copts", []),
)
kwargs["deps"] = kwargs.get("deps", []) + [":" + pchtarget])
kwargs["copts"] = kwargs.get("copts", []) + cc_pch_copts(pchhdr, pchtarget))
native.cc_binary(name=name, **kwargs)
my_cc_binary(
name = "main",
srcs = ["main.cpp", "common.h", "common.cpp"],
pchsrc = "common.cpp",
pchhdr = "common.h",
)
with project being contained of:
main.cpp
#include "common.h"
int main() { std::cout << "Hello world!" << std::endl; return 0; }
common.h
#include <iostream>
common.cpp
#include "common.h"
Questions
The implementation works. However, my discussion points are:
What is the best way to propagate the additional compile flags to dependent targets? The way I solved it via cc_pch_copts seems rather hacky. I would assume it involves defining a provider, but I couldn't find one which allows me to forward flags (CcToolChainConfigInfo has something in this direction but it seems overkill).
Is there another way to get all the compile flags (defines, includes etc.) than what I implemented above? It's really verbose and it most doesn't cover a lot of corner cases. Would it be possible to do something like compiling an empty.cpp file in the cc_pch rule to obtain a provider which gives direct access to all the flags?
Note: I'm aware of the downsides of precompiled headers but this is a large codebase and not using it is unfortunately not an option.
Maybe it can be simplified by generating a dummy cpp just to trigger the generation of the pch file, there is no need to link the resulting obj. (like in qmake): You just define the name of the precomp header, it will generate a dummy precomp.h.cpp and use this to trigger the generation of the pch file.
In VS/msbuild it is also possible to just generate the pch from the precomp.h file (but requires change to the source):
- change the item type of the header to "C/C++ compile"
- set the /Yc option on this
- add a hdrstop directive at the end of precomp.h like
#pragma once
#include <windows.h>
#pragma hdrstop("precomp.h")
Thanks for sharing your bzl files, I'm also looking into this (large code base with precomp headers).
From what I know precompiled headers are especially usefull for framework developers doing lot of template metaprogramming and having a respectable code base. It is not intended to speed up the compilation if you are still in development of the framework. It does not speedup the compile time if the code is poorly designed and every dependencies comes in sequence.
Your files here are only the config file of VC++, the actual job not even started yet and precompiled headers are bytecode.Use parallel build whenever possible.
Also, the resulting headers are HUGE !
Related
How to pass structures into re-integrated autogenerated C++ code in Matlab
I am trying to test some code that has been generated from Matlab into C++. To do this I am attempting to integrate and run the generated C++ code back into Matlab. Here's the function I am trying to use (in Matlab pre-autogen) function out = getRotationMatrix(aStruct) out = aStruct.bank_rad*aStruct.heading_rad+aStruct.pitch_rad; end I autogenerate it using this ... function varargout = AutoGenCode(varargin) % Here we are attempting to generate a C++ class from a matlab function via a % hosting function % initialise varargout = {}; % create instance of config object cfg = coder.config('LIB'); % config options cfg.MaxIdLength = int32(64); cfg.TargetLang = 'C++'; cfg.CppPreserveClasses = 1; cfg.EnableCustomReplacementTypes = true; cfg.ReplacementTypes.uint32 = 'uint32_t'; cfg.CppInterfaceStyle = 'Methods'; cfg.CppInterfaceClassName = 'FrameTransformation'; cfg.FilePartitionMethod = 'MapMFileToCFile'; % or 'MapMFileToCFile' SingleFile cfg.EnableVariableSizing = false; %cfg.PreserveVariableNames = 'UserNames'; % Worse %cfg.IncludeInitializeFcn = true; cfg.PassStructByReference = true; thisStruct.bank_rad = 2.1; thisStruct.heading_rad = 3.1; thisStruct.pitch_rad = 3.1; codegen -config cfg getRotationMatrix -args {thisStruct} -report -preservearraydims -std:c++11 end To move to another area (\unzipped) I use packNGo load([pwd,'\codegen\lib\getRotationMatrix\buildInfo.mat']) packNGo(buildInfo,'packType', 'hierarchical','fileName','portzingbit') Now when i try to re-integrate it i am using clib cd 'D:\thoros\Components\Frame Transformation Service\FT_V2\unzippedCode' clibgen.generateLibraryDefinition('FrameTransformation.h','Libraries',{'getRotationMatrix.lib'}) build(defineFrameTransformation) addpath('D:\thoros\Components\Frame Transformation Service\FT_V2\unzippedCode\FrameTransformation') Where I had to define the < SHAPE > parameter in the defineFrameTransformation.mlx manually to be 1 When i try and use the function I cant pass a structure without an error A = clib.FrameTransformation.FrameTransformation() thisStruct.bank_rad = 2.1; thisStruct.heading_rad = 3.1; thisStruct.pitch_rad = 3.1; >> A.getRotationMatrix(thisStruct) I get the following error Unrecognized method, property, or field 'getRotationMatrix' for class 'clib.FrameTransformation.FrameTransformation'. The problem disappears if rewrite and regenerate the function to accept non-structure input e.g. double. By using the summary function i can see that the call to getRotationMatrix should be of type clib.FrameTransformation.struct0_T However i can't seem to create a variable of this type. summary(defineFrameTransformation) MATLAB Interface to FrameTransformation Library Class clib.FrameTransformation.struct0_T No Constructors defined No Methods defined No Properties defined Class clib.FrameTransformation.FrameTransformation Constructors: clib.FrameTransformation.FrameTransformation() clib.FrameTransformation.FrameTransformation(clib.FrameTransformation.FrameTransformation) Methods: double getRotationMatrix(clib.FrameTransformation.struct0_T) No Properties defined So how is one supposed to pass structures to C++ libraries in Matlab ??? what am i doing wrong. Note Matlab 2020B, windows, Visual studio 2019
Ah, you were so close to the solution :) There was a small catch there. When you are using clibgen.generateLibraryDefinition() you have to make sure that all the type definition are included in the header file. In your case the definition of struct0_T was presnet inside getRotationMatrix_types.h file. So you will have to include both the headers using below command : clibgen.generateLibraryDefinition(["FrameTransformation.h","getRotationMatrix_types.h"],"PackageName","mylib",'Libraries',{'getRotationMatrix.lib'}) Now you will have to fill the additional details required in the definition file. Once you finish that step, you can use below commands to successfully use the interface build(definemylib) addpath('\\mathworks\home\dramakan\MLAnswers\CLIB_With_Codegen\ToPort\portzingbit\mylib') A = clib.mylib.FrameTransformation s = clib.mylib.struct0_T s.bank_rad =2.1; s.heading_rad =3.1; s.pitch_rad=3.1; A.getRotationMatrix(s) I could get below output in R2021b >> A.getRotationMatrix(s) ans = 9.6100 Additionally check if you can use MATLAB Coder MEX instead of doing all these circus. You can call the generated code directly in MATLAB using MEX. You can refer below documentation : https://www.mathworks.com/help/coder/gs/generating-mex-functions-from-matlab-code-at-the-command-line.html
If you have Embedded Coder (the line cfg.ReplacementTypes.uint32 = 'uint32_t' suggests you do), then you can use SIL to do what you're proposing with just a few lines of code: cfg.VerificationMode = 'SIL'; thisStruct.bank_rad = 2.1; thisStruct.heading_rad = 3.1; thisStruct.pitch_rad = 3.1; codegen ... % Now test the generated code. This calls your actual generated code % and automatically does all of the necessary data conversion. The code % is run in a separate process and outputs are returned back % to MATLAB getRotationMatrix_sil(thisStruct) More info is in the doc. If you have tests / scripts already exercising your MATLAB code, you can reuse those with SIL by checking out coder.runTest and the codegen -test option.
How to build static library from the Generated source files using Bazel Build
I am trying to make a following setup run with Bazel. With calling “bazel build” a Python script should generate unknown number of *.cc files with random names, and then compile these into single static library (.a file), all within one Bazel call. I have tried following: one generated file has fixed name, this one is referenced in outs of genrule() and srcs of cc_library rule. The problem is I need all generated files to be built as a library, not only the file with fixed name. Any ideas how to do this? My BUILD file: py_binary( name = "sample_script", srcs = ["sample_script.py"], ) genrule( name = "sample_genrule", tools = [":sample_script"], cmd = "$(location :sample_script)", outs = ["cpp_output_fixed.cc"], #or shall also the files with random names be defined here? ) cc_library( name = "autolib", srcs = ["cpp_output_fixed.cc"], #srcs = glob([ #here should all generated .cc files be named # "./*.cc", # "./**/*.cc", # ])+["cpp_output_fixed.cc"], ) Python file sample_script.py: #!/usr/bin/env python import hashlib import time time_stamp = time.time() time_1 = str(time_stamp) time_2 = str(time_stamp + 1) random_part_1 = hashlib.sha1(time_1).hexdigest()[-4:] random_part_2 = hashlib.sha1(time_1).hexdigest()[-4:] fixed_file = "cpp_output_fixed" + ".cc" file_1 = "cpp_output_" + random_part_1 + ".cc" file_2 = "cpp_output3_" + random_part_2 + ".cc" with open(fixed_file, "w") as outfile: outfile.write("#include <iostream>" "int main() {" " std::cout <<'''Hello_world''' <<std::endl;" " return 0" "}") with open(file_1, "w") as outfile: outfile.write("#include <iostream>" "int main() {" " std::cout <<'''Hello_world''' <<std::endl;" " return 0" "}") with open(file_2, "w") as outfile_new: outfile_new.write("#include <iostream>" "int main() {" " std::cout <<'''Hello_world''' <<std::endl;" " return 0" "}") print ".cc generation DONE"
[big edit, since I found a way to make it work :)] If you really need to emit files that are unknown at the analysis phase, your only way is what we internally call tree artifacts. You can think of it as a directory that contains files that will only be inspected at the execution phase. You can declare a tree artifact from Skylark using ctx.actions.declare_directory. Here is a working example. Note 3 things: we need to add ".cc" to the directory name to fool C++ rules that this is valid input the generator needs to create the directory that bazel tells it to you need to use bazel#HEAD (or bazel 0.11.0 and later) genccs.bzl: def _impl(ctx): tree = ctx.actions.declare_directory(ctx.attr.name + ".cc") ctx.actions.run( inputs = [], outputs = [ tree ], arguments = [ tree.path ], progress_message = "Generating cc files into '%s'" % tree.path, executable = ctx.executable._tool, ) return [ DefaultInfo(files = depset([ tree ])) ] genccs = rule( implementation = _impl, attrs = { "_tool": attr.label( executable = True, cfg = "host", allow_files = True, default = Label("//:genccs"), ) } ) BUILD: load(":genccs.bzl", "genccs") genccs( name = "gen_tree", ) cc_library( name = "main", srcs = [ "gen_tree" ] ) cc_binary( name = "genccs", srcs = [ "genccs.cpp" ], ) genccs.cpp #include <fstream> #include <sys/stat.h> using namespace std; int main (int argc, char *argv[]) { mkdir(argv[1], S_IRWXU); ofstream myfile; myfile.open(string(argv[1]) + string("/foo.cpp")); myfile << "int main() { return 42; }"; return 0; }
1) List all output files. 2) Use the genrule as a dependency to the library. genrule( name = "sample_genrule", tools = [":sample_script"], cmd = "$(location :sample_script)", outs = ["cpp_output_fixed.cc", "cpp_output_0.cc", ...] ) cc_library( name = "autolib", srcs = [":sample_genrule"], )
How can you set up dynamically loaded library dependencies in bazel?
Suppose I have a unit test that uses dlopen to load and call code from a provided shared library int main(int argc, char* argv[]) { const char* library = argv[1]; // calls dlopen with library and does some testing } Given the declared library cc_library( name = "a", srcs = ["a.cpp"], visibility = ["//visibility:public"], ) Is there any way I can use cc_test to set up the unit test to run with the location of library a passed in as an argument? (Preferably also in a platform independent way so that I don't have to worry about what suffix is used for the library)
You might be able to write a custom skylark rule that accesses runfiles (related discussion here). Hacking something together: BUILD: load("//:foo.bzl", "runfiles") cc_binary( name = "liba.so", srcs = [ "a.cc" ], linkshared = 1, ) runfiles( name = "runfiles", deps = [ ":liba.so" ], ) foo.bzl: def _impl(ctx): for dep in ctx.attr.deps: print(dep.files_to_run.executable.path) runfiles = rule( implementation = _impl, attrs = { "deps": attr.label_list(allow_files=True), } )
Why is Cocoapods adding preserved files to compilation?
I have a podspec for a project that contains an embedded C++ library. The podspec looks like this (with the source being local until I get it working and push to GitHub): Pod::Spec.new do |s| s.name = "LibName" s.version = "1.0.0" s.summary = "Summary" s.license = "BSD" s.homepage = "https://homepage.com" s.author = { "Dov Frankel" => "dov#email.com" } s.source = { :git => "/Users/Dov/PathTo/LocalLibrary" } s.ios.deployment_target = "5.0" s.osx.deployment_target = "10.7" s.requires_arc = false s.source_files = "Classes/*.{mm,m,h}", "Libraries/unrar/*.hpp", "Libraries/lib/fileA.cpp", "Libraries/lib/fileB.cpp", s.preserve_paths = "Libraries/lib/fileC.cpp", "Libraries/lib/fileD.cpp" end In the LibName project that gets created, the list of compiled sources includes fileA, fileB, fileC, and fileD. Why is that? The preserve_paths files should only be preserved, not compiled.
D'oh! Remove the trailing comma from fileB.cpp, which apparently causes the preserve_paths to get concatenated onto the end of source_files.
C extension for Tcl built in LabWindows crashing after upgrading to Tcl 8.6
Okay, so we have an extension that is written in C for Tcl 8.4 using LabWindows. After upgrading to Tcl 8.6 calling any procedures that were produced by the dll causes wish to crash without producing a useful error code. This happens from both a script and if I manually load the library and call a procedure from the wish shell. Now, this only happens when I install Tcl 8.6 over 8.4. If I do a fresh install of 8.6 it says the the dll is missing a dependent library. So, I used dependency walker to see that the dll is dependent on tcl84.dll whereas my extensions made with Visual Studio(VS) and even other old LabWindows projects also don't have this listed as a dependency. Any project that doesn't have tcl84.dll listed as a dependency, as you might expect, works fine on Tcl 8.6, both a fresh install and being installed over 8.4. So does anyone have any idea why the extension is dependent on tcl84.dll when others are not? Here's the source: SI.c only up to the init method(entire file is too large) #include <analysis.h> #include "toolbox.h" #include <utility.h> #include <ansi_c.h> #include "SI.h" //////////////////////////////////////////////////////////////////////////////////////////////////// int DLLEXPORT Si_Init(Tcl_Interp *interp) { //////////////////////////////////////////////////////////////////////////////////////////////////// if (Tcl_InitStubs(interp, "8.4", 0) == NULL) { return TCL_ERROR; } //TCL Exported Functions Tcl_CreateObjCommand(interp, "LoadWfm", (Tcl_ObjCmdProc*)LoadWfm,(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "SaveWfm", (Tcl_ObjCmdProc*)SaveWfm,(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "Step2SParam", (Tcl_ObjCmdProc*)Step2SParam,(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "Step2Eye", (Tcl_ObjCmdProc*)Step2Eye,(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_PkgProvide(interp, "SI", "1.0"); return TCL_OK; } SI.h //Exported Functions int DLLEXPORT Si_Init(Tcl_Interp *interp); int DLLEXPORT LoadWfm(ClientData clientData, Tcl_Interp *interp,int objc, Tcl_Obj *CONST objv[]); int DLLEXPORT SaveWfm(ClientData clientData, Tcl_Interp *interp,int objc, Tcl_Obj *CONST objv[]); int DLLEXPORT Step2SParam(ClientData clientData, Tcl_Interp *interp,int objc, Tcl_Obj *CONST objv[]); int DLLEXPORT Step2Eye(ClientData clientData, Tcl_Interp *interp,int objc, Tcl_Obj *CONST objv[]); //Local Functions int StepToSParam (double *vin, double *vout, double dt, int N, double **S_real_out, double **S_imag_out, double *S_f0_out, double *S_df_out, int *S_N_out); double RisetimeToBandwidth_20_80(double x); double RisetimeToBandwidth_10_90(double x); int GaussianFilter(double *Waveform, int Samples, double SampleTime, int BitPoints, double Bandwidth); int NormalizeAmplitude (double *Waveform, int Samples, double Vpp); int FunctionGenerator(int BitPattern[], int PatternLength, int PatternCycles, double Freq, double Vpp, double Risetime, int Risetime2080, double dt, int *Samples, double **Waveform); int ZeroPad (double **wfm, int N, int NewN); int ParZ(double Z1_Re, double Z1_Im, double Z2_Re, double Z2_Im, double *ZT_Re, double *ZT_Im); int ReflCoef(double Z1_Re, double Z1_Im, double Z2_Re, double Z2_Im, double *ZRefl_Re, double *ZRefl_Im); int SixCompEq(double f, double Zcab, double Rld, double R1, double C, double R3, double L, double *T_Re, double *T_Im); int FourCompEq(double f, double Zcab, double Rld, double R1, double C, double R3, double L, double *T_Re, double *T_Im); int ApplyEq(int NumComponents, int EQ_N, double df, double Zcab, double Rld, double R1, double C, double R3, double L, double *T_Re, double *T_Im); int SimulateEye (double *in, double *out, int N, double dt, char *Pattern_String, int Pattern_Inverted, int Pattern_Cycles, double Pattern_BitRate, double Pattern_Risetime, int Pattern_2080, double Pattern_Amplitude, int EQ_NumComponents, double EQ_Zcab, double EQ_Rld, double EQ_R1, double EQ_C, double EQ_R3, double EQ_L, double **Eye_Pattern, double *Eye_dt, int *Eye_N); int FindPatternStartIndex(double *EyeWfm, double Eye_dt, int Eye_N, double Pattern_Bitrate, int Pattern_Bits, int Pattern_Cycles); And if anyone is familiar with LabWindows, here's the project setting files: SI.prj [Project Header] Version = 800 Pathname = "/c/CVS_CHECKOUT/MHTS/SI/SI.prj" CVI Dir = "/c/program files/national instruments/cvi80" IVI Standard Root Dir = "/C/Program Files/IVI" VXIplug&play Framework Dir = "/C/VXIPNP/winnt" Number of Files = 4 Target Type = "Dynamic Link Library" Flags = 16 [File 0001] File Type = "Include" Res Id = 1 Path Is Rel = True Path Rel To = "Project" Path Rel Path = "../Include/molex_tcl.h" Path = "/c/CVS_CHECKOUT/MHTS/Include/molex_tcl.h" Exclude = False Project Flags = 0 Folder = "Included Files" [File 0002] File Type = "CSource" Res Id = 2 Path Is Rel = True Path Rel To = "Project" Path Rel Path = "SI.c" Path = "/c/CVS_CHECKOUT/MHTS/SI/SI.c" Exclude = False Compile Into Object File = False Project Flags = 0 Folder = "Source Files" [File 0003] File Type = "Include" Res Id = 3 Path Is Rel = True Path Rel To = "Project" Path Rel Path = "SI.h" Path = "/c/CVS_CHECKOUT/MHTS/SI/SI.h" Exclude = False Project Flags = 0 Folder = "Source Files" [File 0004] File Type = "Library" Res Id = 4 Path Is Rel = True Path Rel To = "Project" Path Rel Path = "../Include/tclDecls.lib" Path = "/c/CVS_CHECKOUT/MHTS/Include/tclDecls.lib" Exclude = False Project Flags = 0 Folder = "Included Files" [Folders] Include Files Folder Not Added Yet = True User Interface Files Folder Not Added Yet = True Instrument Files Folder Not Added Yet = True Folder 0 = "Source Files" Folder 1 = "Included Files" [Compiler Options] Default Calling Convention = "cdecl" Require Prototypes = True Require Return Values = True Enable Pointer Mismatch Warning = False Enable Unreachable Code Warning = False Enable Unreferenced Identifiers Warning = False Enable Assignment In Conditional Warning = False O Option Compatible With 5.0 = False Uninitialized Locals Compile Warning = "Conservative" [Run Options] Stack Size = 250000 Image Base Address = 4194304 [Compiler Defines] Compiler Defines = "/DWIN32_LEAN_AND_MEAN /D_MSC_VER=1200 /D_WINDEF_" [Include Paths] Include Path 1 Is Rel = False Include Path 1 = "/c/CVS_CHECKOUT/MHTS/Include" Include Path 2 Is Rel = False Include Path 2 = "/c/Tcl/include" [Create Executable] Executable File_Debug Is Rel = True Executable File_Debug Rel To = "Project" Executable File_Debug Rel Path = "SI_dbg.dll" Executable File_Debug = "/c/CVS_CHECKOUT/MHTS/SI/SI_dbg.dll" Executable File_Release Is Rel = True Executable File_Release Rel To = "Project" Executable File_Release Rel Path = "SI.dll" Executable File_Release = "/c/CVS_CHECKOUT/MHTS/SI/SI.dll" Icon File Is Rel = False Icon File = "" Application Title = "" DLL Exports = "Symbols Marked As Export" DLL Import Library Choice = "Gen Lib For Current Mode" Use IVI Subdirectories for Import Libraries = False Use VXIPNP Subdirectories for Import Libraries = False Use Dflt Import Lib Base Name = True Where to Copy DLL = "Do not copy" Add Type Lib To DLL = False Include Type Lib Help Links = False Type Lib FP File Is Rel = False Type Lib FP File = "" Type Lib Guid = "" Runtime Support = "Full Runtime Support" Instrument Driver Support Only = False Embed Project .UIRs = False Generate Map File = False [External Compiler Support] UIR Callbacks File Option = 0 Using LoadExternalModule = False Create Project Symbols File = True UIR Callbacks Obj File Is Rel = False UIR Callbacks Obj File = "" Project Symbols H File Is Rel = False Project Symbols H File = "" Project Symbols Obj File Is Rel = False Project Symbols Obj File = "" [ActiveX Server Options] Specification File Is Rel = False Specification File = "" Source File Is Rel = False Source File = "" Include File Is Rel = False Include File = "" IDL File Is Rel = False IDL File = "" Register ActiveX Server = False [tpcSection] tpcEnabled = 0 tpcOverrideEnvironment = 0 SI.cws [Workspace Header] Version = 800 Pathname = "/c/CVS_CHECKOUT/MHTS/SI/SI.cws" CVI Dir = "/c/program files/national instruments/cvi80" IVI Standard Root Dir = "/C/Program Files/IVI" VXIplug&play Framework Dir = "/C/VXIPNP/winnt" Number of Projects = 1 Active Project = 1 Project 0001 = "SI.prj" Drag Bar Left = 323 Window Top = 137 Window Left = 1190 Window Bottom = 1041 Window Right = 2278 Maximized = True Maximized Children = True Max Number Of Errors = 20 Track Include File Dependencies = True Prompt For Missing Includes = True Stop On First Error File = False Bring Up Err Win For Warnings = True Show Build Dialog = False Save Changes Before Running = "Always" Hide Windows = False Global Hot Key = False Break At First Statement = False Sort Type = "File Name" Number of Opened Files = 3 Window Confinement Region Enabled = True MainColumnWidth = 304 FileDateColumnWidth = 70 FileSizeColumnWidth = 70 StatusColumnWidth = 70 [Project Header 0001] Version = 800 Don't Update DistKit = False Platform Code = 4 Build Configuration = "Release" Warn User If Debugging Release = 1 Batch Build Release = False Batch Build Debug = False Force Rebuild = False [File 0001] Path = "/c/CVS_CHECKOUT/MHTS/SI/SI.c" File Type = "CSource" Disk Date = 3288546022 In Projects = "1," Window Top = 163 Window Left = 78 Window Z-Order = 1 Source Window State = "1,191,191,191,54,55,55,0,0,116,0,25,0,25,0,51,150,0,192,6,349,676,1,0," Breakpoint 0001 = "166,0,enabled," Breakpoint 0002 = "195,0,enabled," [File 0002] Path = "/c/CVS_CHECKOUT/MHTS/SI/SI.h" File Type = "Include" Disk Date = 3262700601 In Projects = "1," Window Top = 30 Window Left = 6 Window Z-Order = 2 Source Window State = "1,27,28,27,0,0,0,0,0,80,0,28,0,28,0,25,0,45,27,130,349,676,1,0," [File 0003] Path = "/c/CVS_CHECKOUT/MHTS/Include/molex_tcl.h" File Type = "Include" Disk Date = 3275700706 In Projects = "1," Window Top = 30 Window Left = 6 Window Z-Order = 3 Source Window State = "1,15,16,16,86,159,159,0,0,80,0,0,0,0,0,25,0,0,35,33,349,676,1,0," [File 0004] Path = "/c/CVS_CHECKOUT/MHTS/Include/tclDecls.lib" File Type = "Library" Disk Date = 3262622625 In Projects = "1," [Build Options 0001] Generate Browse Info = True Enable Uninitialized Locals Runtime Warning = True Debugging Level = "Standard" Break On Library Errors = False Break On First Chance Exceptions = False Execution Target Address = "Local desktop computer" Execution Target Port = 0 Execution Target Type = 0 [SCC Options 0001] Use global settings = True SCC Provider = "" SCC Project = "" Local Path = "" Auxiliary Path = "" Perform Same Action For .h File As For .uir File = "Ask" Username = "" Comment = "" Use Default Username = False Use Default Comment = False Suppress CVI Error Messages = False [DLL Debugging Support 0001] External Process Path = "/c/Tcl/bin/wish.exe" [DLLs Used By Executable 0001] DLL 0001 = "/C/Tcl/bin/tcl84.dll" [Command Line Args 0001] Command Line Args = "" The most promising possibility looks to be this line in the .cws file: [DLLs Used By Executable 0001] DLL 0001 = "/c/Tcl/bin/tcl84.dll" but here is the .cws file from another LabWindows project: OK.cws [Workspace Header] Version = 800 Pathname = "/c/CVS_CHECKOUT/MHTS/OK/OK.cws" CVI Dir = "/c/program files/national instruments/cvi80" IVI Standard Root Dir = "/C/Program Files/IVI" VXIplug&play Framework Dir = "/C/VXIPNP/winnt" Number of Projects = 1 Active Project = 1 Project 0001 = "OK.prj" Drag Bar Left = 181 Window Top = 101 Window Left = 1404 Window Bottom = 974 Window Right = 2676 Maximized = True Maximized Children = True Max Number Of Errors = 20 Track Include File Dependencies = True Prompt For Missing Includes = True Stop On First Error File = False Bring Up Err Win For Warnings = True Show Build Dialog = False Save Changes Before Running = "Always" Hide Windows = False Global Hot Key = False Break At First Statement = False Sort Type = "File Name" Number of Opened Files = 1 Window Confinement Region Enabled = True MainColumnWidth = 162 FileDateColumnWidth = 70 FileSizeColumnWidth = 70 StatusColumnWidth = 70 [Project Header 0001] Version = 800 Don't Update DistKit = False Platform Code = 4 Build Configuration = "Debug" Warn User If Debugging Release = 1 Batch Build Release = False Batch Build Debug = False Force Rebuild = False [File 0001] Path = "/c/CVS_CHECKOUT/MHTS/OK/OK.c" File Type = "CSource" Disk Date = 3291811857 In Projects = "1," Window Top = 59 Window Left = 80 Window Z-Order = 1 Source Window State = "1,503,503,503,14,32,32,0,0,133,0,37,0,51,29,59,478,0,514,78,663,815,1,0," [File 0002] Path = "/c/CVS_CHECKOUT/MHTS/Include/molex_tcl.h" File Type = "Include" Disk Date = 3275700706 In Projects = "1," Window Top = 48 Window Left = 18 Source Window State = "1,8,9,8,0,0,0,0,0,0,0,0,0,0,0,0,1,0,8,12,461,988,1,0," [File 0003] Path = "/c/CVS_CHECKOUT/MHTS/OK/OK.h" File Type = "Include" Disk Date = 3291811853 In Projects = "1," Window Top = 614 Window Left = 299 Source Window State = "1,4,4,4,17,21,17,0,0,0,0,16,0,16,0,0,0,0,15,17,278,676,1,0," [File 0004] Path = "/c/Program Files/Opal Kelly/FrontPanel/API/okFrontPanelDLL.h" File Type = "Include" Disk Date = 3268500132 In Projects = "1," Window Top = 130 Window Left = 11 Source Window State = "1,218,218,218,51,68,51,0,3,0,0,0,0,0,0,0,197,0,218,68,476,725,1,0," [File 0005] Path = "/c/CVS_CHECKOUT/MHTS/Include/tclDecls.lib" File Type = "Library" Disk Date = 3262622625 In Projects = "1," [Build Options 0001] Generate Browse Info = True Enable Uninitialized Locals Runtime Warning = True Debugging Level = "Standard" Break On Library Errors = False Break On First Chance Exceptions = False Execution Target Address = "Local desktop computer" Execution Target Port = 0 Execution Target Type = 0 [SCC Options 0001] Use global settings = True SCC Provider = "" SCC Project = "" Local Path = "" Auxiliary Path = "" Perform Same Action For .h File As For .uir File = "Ask" Username = "" Comment = "" Use Default Username = False Use Default Comment = False Suppress CVI Error Messages = False [DLL Debugging Support 0001] External Process Path = "/c/Tcl/bin/wish.exe" [DLLs Used By Executable 0001] DLL 0001 = "/c/Tcl/bin/tcl84.dll" [Command Line Args 0001] Command Line Args = "" ...it has the same line, yet this project works properly after updating to Tcl 8.6. UPDATE 5/13/2013 9:00 AM - From what I can tell from all the answers and comments so far is that it definitely has to have something to do with some idiosyncratic in the LabWindows build. So, I'll be getting a copy of it hopefully by the end of the work day today and I'll update my question with the results. UPDATE 5/13/2013 2:13 PM - Okay so I got LabWindows and first tried deleting the line in the .cws file and re-compiling. The IDE simply re-generates the line before compiling and ends up with the same result. So, I then created a new project from scratch and brought over only the .c and .h files. I set up all the includes and project settings manually and when I got a successful build I looked at the .cws file and the line had been auto-generated again producing the same results. Therefore, there must some function call or reference in the .c or .h file that is referencing tcl84.dll. Any additional insights would be very much appreciated.
You properly use the Tcl STUBS support with your call to Tcl_InitStubs() but throw the benefits out of the window by linking with Tcl84.dll. If you use Stubs, you only need to link with the stubs version of the oldest DLL you need. In this case the lib called 'tclstub84.lib'. This static library takes care of the magic needed to allow a Tcl 8.6 to load a 8.4 library without recompiling. You probably need the TCL_USE_STUBS compiler define too, to make it work properly. See http://tcl.activestate.com/doc/howto/stubs.html for further details how to properly enable STUBS support for your library.
Deep within SI.cws you have [DLLs Used By Executable 0001] DLL 0001 = "/C/Tcl/bin/tcl84.dll" which looks as though it's where the dependency comes from. That's the easy bit. I'm unfamiliar LabWindows and VisualStudio, so I have no informed idea what you should do to resolve this. Mind you, changing the above line to specify tcl86.dll looks tempting :-)